From a language design perspective, is it easier to build a compiler that considers `;` or newline as the end-of-statement operator, or one that works like Lua, where statements can appear anywhere?
From a language design point of view, the hard thing about newline as a statement terminator is how to deal with expressions that span multiple lines. In shell you have to use explicit line continuations. In Python, the line breaks are ignored if they are inside parenthesis (which is one of the reasons why it doesn't allow multi-line lambdas). Javascript deals with it by having an ad-hoc semicolon insertion algorithm.
The way Lua does it is closer to what you might be taught if you take a compilers class. It's just a plain old context free grammar. The tricky bit was designing the grammar so that semicolons were not needed. You have to be careful when there is something that could either be parsed as a continuation of the previous statement or as the start of the next statement. One place where Lua does this is in the rule that the return statement must be the last in the block. Another is that not every expression can appear as the function part of a function call. For example, something like 1() is a syntax error because the grammar doesn't allow function calls where the function is a numeric literal.