diff --git a/lexer.v b/lexer.v index 5822f86..afe6565 100644 --- a/lexer.v +++ b/lexer.v @@ -26,6 +26,12 @@ enum TokenType as u8 { greater_eq less_eq not_eq + plus_eq + minus_eq + star_eq + slash_eq + increment + decrement lparen rparen lsqparen @@ -46,43 +52,7 @@ struct Token { } fn str_from_toktype(type TokenType) string { - return match type { - .integer {'integer'} - .real {'real'} - .boolean {'boolean'} - .kw_let {'let'} - .type {'type'} - .kw_if {'if'} - .kw_else {'else'} - .kw_for {'for'} - .kw_break {'break'} - .kw_fn {'fn'} - .kw_return {'return'} - .identifier {'identifier'} - .eof {'EOF'} - .unknown {'unknown'} - .plus {'plus'} - .minus {'minus'} - .star {'star'} - .slash {'slash'} - .equals {'equals'} - .less {'less'} - .greater {'greater'} - .lparen {'lparen'} - .rparen {'rparen'} - .lsqparen {'lsqparen'} - .rsqparen {'rsqparen'} - .lbracket {'lbracket'} - .rbracket {'rbracket'} - .dot {'dot'} - .comma {'comma'} - .semicolon {'semicolon'} - .colon {'colon'} - .eq_eq {'eq eq'} - .greater_eq {'greater eq'} - .less_eq {'less eq'} - .not_eq {'not eq'} - } + return type.str() } fn toktype_from_delimiter(delimiter string) TokenType { @@ -108,6 +78,12 @@ fn toktype_from_delimiter(delimiter string) TokenType { '>=' {.greater_eq} '<=' {.less_eq} '!=' {.not_eq} + '+=' {.plus_eq} + '-=' {.minus_eq} + '*=' {.star_eq} + '/=' {.slash_eq} + '++' {.increment} + '--' {.decrement} else {.unknown} } } @@ -175,7 +151,7 @@ fn lex(input string) ?[]Token { mut tok_str := input[right].ascii_str() if right + 1 < input.len { combined := input.substr(right, right + 2) - if combined in ['==', '>=', '<=', '!='] { + if combined in ['==', '>=', '<=', '!=', '+=', '-=', '*=', '/=', '++', '--'] { tok_str = combined right++ } diff --git a/parser.v b/parser.v index 2f65d86..73fbc3e 100644 --- a/parser.v +++ b/parser.v @@ -70,10 +70,15 @@ fn (mut s SymbolTable) is_in_global_scope() bool { // ------------------------------------------- Expressions -type Expr = VoidExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr +type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | Variable | TypeExpr | Function | TypeCast | ParenExpr struct VoidExpr {} +struct UnaryExpr { + ident string + op string +} + struct BinaryExpr { left Expr op string @@ -201,8 +206,8 @@ fn (mut p Parser) parse_primary() Expr { .integer {IntegerLiteral{token.text.int()}} .real {RealLiteral{token.text.f32()}} .boolean {BoolLiteral{token.text == 'true'}} - .identifier {Variable{token.text}} .kw_fn {Function{token.text}} + .identifier {p.parse_ident(token.text)} .type {p.parse_type(token.text)} .lparen {p.parse_paren()} else {parse_error("Unexpected Token")} @@ -213,13 +218,21 @@ fn (mut p Parser) parse_expr() Expr { mut left := p.parse_primary() match p.peek().type { - .plus, .minus, .star, .slash, .equals, .eq_eq, .not_eq, .less_eq, .greater_eq { + .plus, .minus, .star, .slash, .equals, .eq_eq, .not_eq, .less_eq, .greater_eq, + .plus_eq, .minus_eq, .star_eq, .slash_eq { return p.parse_binary(left, p.peek().text) } else {return left} } } +fn (mut p Parser) parse_ident(ident string) Expr { + return match p.peek().type { + .increment, .decrement {UnaryExpr {ident: ident, op: p.next().text}} + else {Variable{ident}} + } +} + fn (mut p Parser) parse_binary(left Expr, op string) BinaryExpr { p.next() right := p.parse_expr() @@ -227,6 +240,7 @@ fn (mut p Parser) parse_binary(left Expr, op string) BinaryExpr { if !p.is_op_valid_for_type(p.get_expr_type(left), op) { parse_error("Illegal operation ${op} for type ${p.get_expr_type(left)}") } + p.check_binary_expr_types(binary_expr) return binary_expr } @@ -252,6 +266,14 @@ fn (mut p Parser) parse_paren() ParenExpr { return ParenExpr{expr: expr} } +fn (mut p Parser) check_binary_expr_types(expr BinaryExpr) { + left_t := p.get_expr_type(expr.left) + right_t := p.get_expr_type(expr.right) + if left_t != right_t { + parse_error ('Type mismatch in expression: ${left_t} and ${right_t}') + } +} + fn (mut p Parser) get_expr_type(expr Expr) string { return match expr { ParenExpr {p.get_expr_type(expr.expr)} @@ -260,11 +282,8 @@ fn (mut p Parser) get_expr_type(expr Expr) string { BoolLiteral {'bool'} VoidExpr {'void'} BinaryExpr { + p.check_binary_expr_types(expr) left_t := p.get_expr_type(expr.left) - right_t := p.get_expr_type(expr.right) - if left_t != right_t { - parse_error ('Type mismatch in expression: ${left_t} and ${right_t}') - } if expr.op in ['<=', '==', '>=', '!='] { 'bool' } else { @@ -288,8 +307,7 @@ fn (mut p Parser) get_expr_type(expr Expr) string { fn (mut p Parser) is_op_valid_for_type(type string, op string) bool { global := ['=', '==', '!='] mut legal_ops := match type { - 'int' {['+', '-', '*', '/', '<', '>', '<=', '>=',]} - 'real' {['+', '-', '*', '/', '<', '>', '<=', '>=']} + 'int', 'real' {['+', '-', '*', '/', '<', '>', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=']} 'bool' {['=']} else {[]} } diff --git a/test.one b/test.one index 916d105..f01d57c 100644 --- a/test.one +++ b/test.one @@ -1 +1,3 @@ -let a bool = 2 <= 4; +let a int = 2; +a++; +a *= 3.6 + 1.1;