UnaryExpr and fix type check for BynaryExpr

This commit is contained in:
uan
2026-02-04 19:11:08 +01:00
parent fc79c23b77
commit 541d3c7c7f
3 changed files with 44 additions and 48 deletions

52
lexer.v
View File

@@ -26,6 +26,12 @@ enum TokenType as u8 {
greater_eq greater_eq
less_eq less_eq
not_eq not_eq
plus_eq
minus_eq
star_eq
slash_eq
increment
decrement
lparen lparen
rparen rparen
lsqparen lsqparen
@@ -46,43 +52,7 @@ struct Token {
} }
fn str_from_toktype(type TokenType) string { fn str_from_toktype(type TokenType) string {
return match type { return type.str()
.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'}
}
} }
fn toktype_from_delimiter(delimiter string) TokenType { fn toktype_from_delimiter(delimiter string) TokenType {
@@ -108,6 +78,12 @@ fn toktype_from_delimiter(delimiter string) TokenType {
'>=' {.greater_eq} '>=' {.greater_eq}
'<=' {.less_eq} '<=' {.less_eq}
'!=' {.not_eq} '!=' {.not_eq}
'+=' {.plus_eq}
'-=' {.minus_eq}
'*=' {.star_eq}
'/=' {.slash_eq}
'++' {.increment}
'--' {.decrement}
else {.unknown} else {.unknown}
} }
} }
@@ -175,7 +151,7 @@ fn lex(input string) ?[]Token {
mut tok_str := input[right].ascii_str() mut tok_str := input[right].ascii_str()
if right + 1 < input.len { if right + 1 < input.len {
combined := input.substr(right, right + 2) combined := input.substr(right, right + 2)
if combined in ['==', '>=', '<=', '!='] { if combined in ['==', '>=', '<=', '!=', '+=', '-=', '*=', '/=', '++', '--'] {
tok_str = combined tok_str = combined
right++ right++
} }

View File

@@ -70,10 +70,15 @@ fn (mut s SymbolTable) is_in_global_scope() bool {
// ------------------------------------------- Expressions // ------------------------------------------- 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 VoidExpr {}
struct UnaryExpr {
ident string
op string
}
struct BinaryExpr { struct BinaryExpr {
left Expr left Expr
op string op string
@@ -201,8 +206,8 @@ fn (mut p Parser) parse_primary() Expr {
.integer {IntegerLiteral{token.text.int()}} .integer {IntegerLiteral{token.text.int()}}
.real {RealLiteral{token.text.f32()}} .real {RealLiteral{token.text.f32()}}
.boolean {BoolLiteral{token.text == 'true'}} .boolean {BoolLiteral{token.text == 'true'}}
.identifier {Variable{token.text}}
.kw_fn {Function{token.text}} .kw_fn {Function{token.text}}
.identifier {p.parse_ident(token.text)}
.type {p.parse_type(token.text)} .type {p.parse_type(token.text)}
.lparen {p.parse_paren()} .lparen {p.parse_paren()}
else {parse_error("Unexpected Token")} else {parse_error("Unexpected Token")}
@@ -213,13 +218,21 @@ fn (mut p Parser) parse_expr() Expr {
mut left := p.parse_primary() mut left := p.parse_primary()
match p.peek().type { 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) return p.parse_binary(left, p.peek().text)
} }
else {return left} 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 { fn (mut p Parser) parse_binary(left Expr, op string) BinaryExpr {
p.next() p.next()
right := p.parse_expr() 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) { 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)}") parse_error("Illegal operation ${op} for type ${p.get_expr_type(left)}")
} }
p.check_binary_expr_types(binary_expr)
return binary_expr return binary_expr
} }
@@ -252,6 +266,14 @@ fn (mut p Parser) parse_paren() ParenExpr {
return ParenExpr{expr: expr} 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 { fn (mut p Parser) get_expr_type(expr Expr) string {
return match expr { return match expr {
ParenExpr {p.get_expr_type(expr.expr)} ParenExpr {p.get_expr_type(expr.expr)}
@@ -260,11 +282,8 @@ fn (mut p Parser) get_expr_type(expr Expr) string {
BoolLiteral {'bool'} BoolLiteral {'bool'}
VoidExpr {'void'} VoidExpr {'void'}
BinaryExpr { BinaryExpr {
p.check_binary_expr_types(expr)
left_t := p.get_expr_type(expr.left) 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 ['<=', '==', '>=', '!='] { if expr.op in ['<=', '==', '>=', '!='] {
'bool' 'bool'
} else { } 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 { fn (mut p Parser) is_op_valid_for_type(type string, op string) bool {
global := ['=', '==', '!='] global := ['=', '==', '!=']
mut legal_ops := match type { mut legal_ops := match type {
'int' {['+', '-', '*', '/', '<', '>', '<=', '>=',]} 'int', 'real' {['+', '-', '*', '/', '<', '>', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=']}
'real' {['+', '-', '*', '/', '<', '>', '<=', '>=']}
'bool' {['=']} 'bool' {['=']}
else {[]} else {[]}
} }

View File

@@ -1 +1,3 @@
let a bool = 2 <= 4; let a int = 2;
a++;
a *= 3.6 + 1.1;