private Expr Unary() { if (Match(TokenType.NOT, TokenType.MINUS)) { Token op = Previous; Expr right = Cast(); if (right is Expr.Literal lit) { var type = new TypeSpecifier { Type = lit.Type, Dimensions = 0 }; if (op.Type == TokenType.NOT) { if (type.IsBool()) { bool value = (bool)lit.Value; return(new Expr.Literal(lit.Type, !value)); } else { throw Error("Trying to invert a non-boolean value"); } } else { if (type.IsInt()) { long value = (long)lit.Value; return(new Expr.Literal(lit.Type, -value)); } else if (type.IsFloat()) { double value = (double)lit.Value; return(new Expr.Literal(lit.Type, -value)); } else { throw Error("Trying to negate a non-numeric value"); } } } return(new Expr.Unary(op, right)); } return(Invoke()); }
private Expr Relational() { var expr = Additive(); while (Match(TokenType.GREATER, TokenType.GREATER_EQUAL, TokenType.LESS, TokenType.LESS_EQUAL)) { Token op = Previous; Expr right = Additive(); if (expr is Expr.Literal l && right is Expr.Literal r) { var typel = new TypeSpecifier { Type = l.Type, Dimensions = 0 }; var typer = new TypeSpecifier { Type = r.Type, Dimensions = 0 }; if (typer.ImplicitCastableTo(typel)) { if (typel.Type == TypeEnum.BOOL) { throw Error($"Boolean values are not comparable with '{op.Type}'"); } if (typel.IsInt()) { return(CompareLiterals <long>(op.Type, l.Value, r.Value)); } else if (typel.IsFloat()) { return(CompareLiterals <double>(op.Type, l.Value, r.Value)); } else { throw Error("Something wrong with literal comparison"); } } else { throw Error($"'{typer}' not implicitly castable to '{typel}'"); } } expr = new Expr.Binary(expr, op, right); } return(expr); }
private Stmt ForStatement() { Consume(TokenType.LEFT_PARENTH, "Expect '(' after 'for'"); TypeSpecifier type = TypeSpec("Must declare loop variable type"); Token identifier = Consume(TokenType.IDENTIFIER, "Expect identifier after type specifier"); Consume(TokenType.IN, "Expect 'in' after loop variable identifier"); bool istart; bool iend; if (Match(TokenType.LEFT_BRACKET)) { istart = true; } else if (Match(TokenType.LEFT_PARENTH)) { istart = false; } else { throw Error("Expected '[' or '(' at range start"); } Expr start = Expression(); Consume(TokenType.RANGE, "Expect '..' after range start expression"); Expr end = Expression(); if (Match(TokenType.RIGHT_BRACKET)) { iend = true; } else if (Match(TokenType.RIGHT_PARENTH)) { iend = false; } else { throw Error("Expected ']' or ')' at range end"); } Consume(TokenType.RIGHT_PARENTH, "Expect ')' to finish for loop header"); var block = Block(); return(new Stmt.For(type, identifier, new Expr.Range(istart, iend, start, end), block)); }
private Stmt FunctionDeclaration() { try { TypeSpecifier typeSpecifier = TypeSpec("Function declarations must begin with a type specifier"); Token name = Consume(TokenType.IDENTIFIER, "Functions must have names"); var paramList = ParameterList(name.Source); var functBody = Block(); return(new Stmt.FunctionDeclaration(typeSpecifier, name, paramList, functBody)); } catch (Exception) { return(null); } }
private Stmt VariableDeclaration() { TypeSpecifier type = TypeSpec(""); Token identifier = Consume(TokenType.IDENTIFIER, "No identifier for variable declaration"); Binding binding = null; Expr initializer = null; if (Match(TokenType.ON)) { binding = Binding(); } if (Match(TokenType.ASSIGN)) { initializer = VariableInitializer(); } Consume(TokenType.SEMICOLON, "Variable declarations end with a ';'"); return(new Stmt.VariableDeclaration(type, identifier, binding, initializer)); }
private Expr Equality() { var expr = Relational(); while (Match(TokenType.NOT_EQUAL, TokenType.EQUAL)) { Token op = Previous; Expr right = Relational(); if (expr is Expr.Literal l && right is Expr.Literal r) { var typel = new TypeSpecifier { Type = l.Type, Dimensions = 0 }; var typer = new TypeSpecifier { Type = r.Type, Dimensions = 0 }; if (typer.ImplicitCastableTo(typel)) { if (op.Type == TokenType.NOT_EQUAL) { return(new Expr.Literal(TypeEnum.BOOL, !l.Value.Equals(r.Value))); } else { return(new Expr.Literal(TypeEnum.BOOL, l.Value.Equals(r.Value))); } } else { throw Error($"'{typer}' not implicitly castable to '{typel}'"); } } expr = new Expr.Binary(expr, op, right); } return(expr); }
private Expr Primary() { if (Match(TokenType.TRUE)) { return(new Expr.Literal(TypeEnum.BOOL, true)); } if (Match(TokenType.FALSE)) { return(new Expr.Literal(TypeEnum.BOOL, false)); } if (Match(TokenType.INTEGER)) { long num = (long)Previous.Value; return(new Expr.Literal(TypeSpecifier.IntFromConst(num), num)); } if (Match(TokenType.FLOAT)) { double num = (double)Previous.Value; return(new Expr.Literal(TypeSpecifier.FloatFromConst(num), num)); } if (Match(TokenType.STRING)) { string value = (string)Previous.Value; return(new Expr.Literal(TypeEnum.STRING, Regex.Unescape(value))); } if (Match(TokenType.CHAR)) { return(new Expr.Literal(TypeEnum.I8, Previous.Value)); } if (Match(TokenType.IDENTIFIER)) { Token identifier = Previous; if (NextIsType(TokenType.LEFT_BRACKET)) { List <Expr> expressions = new List <Expr>(); while (Match(TokenType.LEFT_BRACKET)) { var expr = Expression(); Consume(TokenType.RIGHT_BRACKET, "Expect ']' after array access expression"); expressions.Add(expr); } return(new Expr.IndexAccess(identifier, expressions)); } return(new Expr.Variable(identifier)); } if (Match(TokenType.LEFT_PARENTH)) { var expr = Expression(); Consume(TokenType.RIGHT_PARENTH, "Expect ')' after grouping expression"); return(new Expr.Grouping(expr)); } throw Error("Expect expression"); }
private Expr Multiplicative() { var expr = Cast(); while (Match(TokenType.DIV, TokenType.MULT)) { Token op = Previous; Expr right = Cast(); if (expr is Expr.Literal l && right is Expr.Literal r) { var typel = new TypeSpecifier { Type = l.Type, Dimensions = 0 }; var typer = new TypeSpecifier { Type = r.Type, Dimensions = 0 }; if (typer.ImplicitCastableTo(typel)) { if (typel.IsInt()) { long one = (long)l.Value; long two = (long)r.Value; if (op.Type == TokenType.DIV) { return(new Expr.Literal(typel.Type, one / two)); } else { return(new Expr.Literal(typel.Type, one * two)); } } else if (typel.IsFloat()) { double one = (double)l.Value; double two = (double)r.Value; if (op.Type == TokenType.DIV) { return(new Expr.Literal(typel.Type, one / two)); } else { return(new Expr.Literal(typel.Type, one * two)); } } else { throw Error("Something wrong on Multiplicative"); } } else { throw Error($"'{typer}' not implicitly castable to '{typel}'"); } } expr = new Expr.Binary(expr, op, right); } return(expr); }