diff --git a/parse.js b/parse.js index 9746b7c..873ee63 100644 --- a/parse.js +++ b/parse.js @@ -193,26 +193,28 @@ error = this.tokenStream.consume(lex.TokenType.Word, "on").error; if (error) return this.getError(error); - let condition; - ({ ast:condition, error } = this.exprInBrackets()); + let target; + ({ ast:target, error } = this.expression()); if (error) return this.getError(error, true); - let trueCase; - ({ ast:trueCase, error } = this.attemptSubtree(this.block)); + let eventName; + ({ token:eventName, error } = this.tokenStream.consume(lex.TokenType.Word)); if (error) return this.getError(error, true); - let ret = { ast: { node: ASTNode.If, condition: condition, trueCase: trueCase }, error: null }; - - if (!this.tokenStream.consume(lex.TokenType.Word, "else").error) + let eventParams; + ({ args:eventParams, error } = this.funcParams(true, true)); + if (error) { - let falseCase; - ({ ast:falseCase, error } = this.attemptSubtree(this.block)); - if (error) return this.getError(error, true); - - ret.ast.falseCase = falseCase; + eventParams = []; + if (error.expectingMatch) + { + return this.getError(error); + } } - return ret; + let body; + ({ ast:body, error } = this.attemptSubtree(this.block)); + if (error) return this.getError(error, true); } forStmt() @@ -295,6 +297,56 @@ let error, bestError, numMatched, bestNumMatched = 0; } + funcParams(consumeOpeningBracket, hasClosingBracket) + { + let error; + if (consumeOpeningBracket) + { + if (error = this.tokenStream.consume(lex.TokenType.Op, "(").error) + { + if (error) return this.getError(error); + } + } + + /* Parsing a function call + * lhs represents the function we are calling + * We need to parse a list of expression separated by , as the arguments + */ + let args = []; + while (true) + { + // peek the next op + let { token:nextToken, type:nextType, pos:nextPos, error } = this.tokenStream.peek(); + if (error) return this.getError(error, true); + + if (hasClosingBracket && nextType == lex.TokenType.Op && nextToken == ")") + { + // no more arguments, we should end the call (after consuming the bracket) + this.tokenStream.consume(); + break; + } + + if (args.length > 0) + { + if (error = this.tokenStream.consume(lex.TokenType.Op, ",").error) + { + if (!hasClosingBracket) break; + return this.getError(error, true); + } + } + + let arg; + // avoid re-declaring error... annoying + ({ ast:arg, error } = this.attemptSubtree(this.expression)); + if (error) return this.getError(error); + + // our new node is the old lhs as a function, called with the index expression + args.push(arg); + } + + return { args: args, error: null }; + } + expression() { let result = this.attemptSubtree(this.expressionInternal, 0); @@ -434,7 +486,7 @@ break; } - //... or our current lhs, in which case we get to consume the token + //... or our current lhs, in which case we consume the bracket this.tokenStream.consumeCount(opToken.length); if (opToken == "[") @@ -457,41 +509,11 @@ } else if (opToken == "(") { - /* Parsing a function call - * lhs represents the function we are calling - * We need to parse a list of expression separated by , as the arguments - */ - let args = []; - while (true) - { - // peek the next op - let { token:nextToken, type:nextType, pos:nextPos, error } = this.tokenStream.peek(); - if (error) return this.getError(error); - - if (nextType == lex.TokenType.Op && nextToken == ")") - { - // no more arguments, we should end the call (after consuming the bracket) - this.tokenStream.consume(); - break; - } - - if (args.length > 0) - { - if (error = this.tokenStream.consume(lex.TokenType.Op, ",").error) - { - return this.getError(error); - } - } - - { - // avoid re-declaring error... annoying - let { ast:arg, error } = this.attemptSubtree(this.expression); - if (error) return this.getError(error); - - // our new node is the old lhs as a function, called with the index expression - args.push(arg); - } - } + // funcParams consumes the first ( token for us + // false = don't consume opening bracket (we already did) + // true = need closing bracket + let { args, error } = this.funcParams(false, true); + if (error) return this.getError(error, true); // generate the AST node lhs = {node:ASTNode.Call, func:lhs, args:args};