referencing and methods

This commit is contained in:
uan
2026-02-07 19:14:48 +01:00
parent 005828cec2
commit a3b978a09d
5 changed files with 269 additions and 39 deletions

188
parser.v
View File

@@ -45,6 +45,8 @@ struct FuncSymbolInfo {
struct ClassSymbolInfo {
name string
members_info map[string]VarSymbolInfo
mut:
methods_info map[string]FuncSymbolInfo
}
struct SymbolTable {
@@ -112,6 +114,19 @@ fn (mut s SymbolTable) lookup_class(name string) ?ClassSymbolInfo {
return none
}
fn (mut s SymbolTable) define_method(name string, class_name string, typ string, block Block) {
if s.lookup_class(class_name) == none {parse_error("Undefined class ${class_name}")}
s.structs[class_name].methods_info[name] = FuncSymbolInfo{type: typ, block: block}
}
fn (mut s SymbolTable) lookup_method(name string, class_name string) ?FuncSymbolInfo {
mut classinfo := s.lookup_class(class_name) or {parse_error("Undefined class ${class_name}")}
if name in classinfo.methods_info {
return classinfo.methods_info[name]
}
return none
}
fn (mut s SymbolTable) is_in_global_scope() bool {
return s.variable_scopes.len == 1
}
@@ -121,10 +136,18 @@ fn (mut s SymbolTable) is_in_global_scope() bool {
type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | StringLiteral |
Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | ClassMember |
ClassInstantiation | MemberAccess
ClassInstantiation | MemberAccess | MethodCall | RefExpr | DerefExpr
struct VoidExpr {}
struct RefExpr {
expr Expr
}
struct DerefExpr {
expr Expr
}
struct UnaryExpr {
expr Expr
op string
@@ -169,6 +192,7 @@ struct ClassMember {
struct MemberAccess {
from Expr
from_type string
member string
member_type string
}
@@ -201,6 +225,14 @@ struct FnCall {
args []Expr
}
struct MethodCall {
from Expr
from_type string
method string
ret_type string
args []Expr
}
// ------------------------------------------- Statements
type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | IfStmt | ElseStmt | ElifStmt | FuncDecl | Param |
@@ -218,6 +250,7 @@ struct FuncDecl {
params []Param
ret_type string
block Block
class_name ?string //if it is a method
}
struct ClassDecl {
@@ -334,6 +367,8 @@ fn (mut p Parser) parse_primary() Expr {
.lparen {p.parse_paren()}
.kw_print {p.parse_print()}
.plus, .minus {p.parse_unary_left(token.text)}
.kw_ref {p.parse_ref()}
.kw_deref {p.parse_deref()}
else {parse_error("Unexpected Token")}
}
}
@@ -368,13 +403,66 @@ fn (mut p Parser) parse_ident(ident string) Expr {
}
}
fn (mut p Parser) parse_member_access(from Expr) MemberAccess {
fn (mut p Parser) parse_ref() RefExpr {
p.expect(.lparen)
expr := p.parse_expr(.prefix)
match expr {
IntegerLiteral, StringLiteral,
RealLiteral, BoolLiteral {parse_error("Cannot get reference of literal value")}
else {}
}
p.expect(.rparen)
return RefExpr{expr: expr}
}
fn (mut p Parser) parse_deref() DerefExpr {
p.expect(.lparen)
expr := p.parse_expr(.prefix)
if !p.get_expr_type(expr).contains('*') {
parse_error('cannot dereference a variable of type ${p.get_expr_type(expr)} (not a reference)')
}
p.expect(.rparen)
return DerefExpr{expr: expr}
}
fn (mut p Parser) parse_member_access(from Expr) Expr {
if p.get_expr_type(from).count('*') > 1 {
base_class_name := p.get_expr_type(from).replace('*', '')
parse_error("Tried accessing member from object of type (${p.get_expr_type(from)}). \
You can only access members from objects of type (${base_class_name}) \
or (${base_class_name}*)")
}
member_tok := p.next()
if member_tok.type != .identifier {parse_error("Expected identifier after member access")}
from_class := p.symbols.lookup_class(p.get_expr_type(from)) or {panic("Accessing member from non-class type")}
base_class_name := p.get_expr_type(from).replace('*', '')
from_class := p.symbols.lookup_class(base_class_name) or {parse_error("Accessing member from non-class type")}
if p.peek().type == .lparen {
if p.get_expr_type(from).contains('*') {
parse_error("Cannot call method on a reference")
}
methodinfo := p.symbols.lookup_method(member_tok.text, base_class_name) or {
dump(p.symbols)
parse_error("Calling undefined method ${member_tok.text}")
}
call := p.parse_call(member_tok.text)
return MethodCall{
from: from
from_type: p.get_expr_type(from)
method: member_tok.text
ret_type: methodinfo.type
args: call.args
}
}
if !(member_tok.text in from_class.members_info) {panic("Accessing undefined member ${member_tok.text}")}
member_type := from_class.members_info[member_tok.text].type
return MemberAccess {from: from, member: member_tok.text, member_type: member_type}
return MemberAccess {
from: from,
from_type: p.get_expr_type(from)
member: member_tok.text,
member_type: member_type
}
}
fn (mut p Parser) parse_class_member() ClassMember {
@@ -386,17 +474,20 @@ fn (mut p Parser) parse_class_member() ClassMember {
member_name := p.peek().text
p.expect(.identifier)
type_tok := p.peek()
type_tok := p.next()
type_name := match type_tok.type {
.type {type_tok.text}
.identifier {
p.expect_ident_is_class(type_tok.text)
type_tok.text
}
.kw_ref {
ref_expr := p.parse_ref()
p.get_expr_type(ref_expr)
}
else{parse_error("Expected type after class member ${member_name} in declaration, got ${p.peek().type}")}
}
p.next()
p.expect(.semicolon)
return ClassMember{name: member_name, type: type_name is_immutable: is_immut}
}
@@ -531,7 +622,8 @@ fn (mut p Parser) get_expr_is_immutable(expr Expr) bool {
UnaryExpr {p.get_expr_is_immutable(expr.expr)}
TypeCast {p.get_expr_is_immutable(expr.expr)}
MemberAccess {
classinfo := p.symbols.lookup_class(p.get_expr_type(expr.from)) or {parse_error("Invalid class")}
clean_class_name := p.get_expr_type(expr.from).replace('*', '')
classinfo := p.symbols.lookup_class(clean_class_name) or {parse_error("Invalid class")}
memberinfo := classinfo.members_info[expr.member] or {parse_error("Undefined member ${expr.member}")}
memberinfo.is_immutable
}
@@ -545,6 +637,11 @@ fn (mut p Parser) get_expr_is_immutable(expr Expr) bool {
fn (mut p Parser) get_expr_type(expr Expr) string {
return match expr {
RefExpr {p.get_expr_type(expr.expr)+'*'}
DerefExpr {
exprtype := p.get_expr_type(expr.expr)
exprtype[..exprtype.len-1]
}
ParenExpr {p.get_expr_type(expr.expr)}
IntegerLiteral {'int'}
RealLiteral {'real'}
@@ -569,10 +666,16 @@ fn (mut p Parser) get_expr_type(expr Expr) string {
return info.type
}
TypeCast {expr.type}
FnCall {
FnCall {
fninfo := p.symbols.lookup_func(expr.name) or {parse_error("Tried to call undefined function ${expr.name}")}
fninfo.type
}
MethodCall {
methodinfo := p.symbols.lookup_method(expr.method, p.get_expr_type(expr.from)) or {
parse_error("Tried to call undefined method ${expr.method}")
}
methodinfo.type
}
MemberAccess {
expr.member_type
}
@@ -643,9 +746,13 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
type_name := match type_tok.type {
.type {type_tok.text}
.identifier {
p.expect_ident_is_class(type_tok.text)
type_tok.text
}
p.expect_ident_is_class(type_tok.text)
type_tok.text
}
.kw_ref {
ref_expr := p.parse_ref()
p.get_expr_type(ref_expr)
}
else{parse_error("Expected variable type after name when declaring ${name_tok.text}")}
}
@@ -655,12 +762,12 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
if type_tok.text == 'void' {
parse_error("Cannot declare a variable of type void")
}
if p.get_expr_type(val) != type_tok.text {
parse_error("Mismatch between declared type (${type_tok.text}) and actual type (${p.get_expr_type(val)})")
if p.get_expr_type(val) != type_name {
parse_error("Mismatch between declared type (${type_name}) and actual type (${p.get_expr_type(val)})")
}
p.expect(.semicolon)
p.symbols.define_var(name_tok.text, type_tok.text, is_const)
p.symbols.define_var(name_tok.text, type_name, is_const)
return VarDecl {
name: name_tok.text
@@ -676,7 +783,17 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
p.expect(.kw_fn)
mut class_name := ?string(none)
if p.peek().type == .lparen {
p.next()
classname_tok := p.peek()
p.expect(.identifier)
class_name = classname_tok.text
p.expect(.rparen)
}
name_tok := p.next()
if name_tok.type != .identifier {
parse_error("Expected function name after let")
}
@@ -689,20 +806,26 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
if p.peek().type != .rparen {
for {
if p.peek().type != .identifier {parse_error("Invalid syntax to declare function arguments! use f(myint int, myreal real)")}
if p.peek().type != .identifier {
parse_error("Invalid syntax to declare function arguments!\
use f(myint int, myreal real)")
}
p_name := p.next().text
//if p.peek().type != .type {parse_error("Invalid syntax to declare function arguments! use f(myint int, myreal real)")}
type_tok := p.peek()
type_tok := p.next()
p_type := match type_tok.type {
.type {type_tok.text}
.identifier {
p.expect_ident_is_class(type_tok.text)
type_tok.text
}
else{parse_error("Expected argument type after name when declaring ${p_name}")}
}
.kw_ref {
ref_expr := p.parse_ref()
dump(p.peek())
p.get_expr_type(ref_expr)
}
else{parse_error("Expected argument type after name when declaring ${p_name}")}
}
p.next()
params << Param{p_name, p_type}
p.symbols.define_var(p_name, p_type, false)
@@ -716,19 +839,27 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
p.expect(.rparen)
p.dump_token()
type_tok := p.next()
ret_type := match type_tok.type {
.type {type_tok.text}
.identifier {
p.expect_ident_is_class(type_tok.text)
type_tok.text
}
else{parse_error("Expected function return type after name when declaring ${name_tok.text}")}
}
.kw_ref {
ref_expr := p.parse_ref()
p.get_expr_type(ref_expr)
}
else{parse_error("Expected function return type after name when declaring ${name_tok.text}")}
}
p.symbols.define_func(name_tok.text, type_tok.text, Block{})
if class_name != none {
p.symbols.define_method(name_tok.text, class_name, type_tok.text, Block{})
p.symbols.define_var('this', class_name+'*', false)
params << Param{'this', class_name+'*'}
} else {
p.symbols.define_func(name_tok.text, type_tok.text, Block{})
}
block := p.parse_block(true)
@@ -743,13 +874,18 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
p.symbols.variable_scopes.delete_last()
p.symbols.define_func(name_tok.text, type_tok.text, block)
if class_name != none {
p.symbols.define_method(name_tok.text, class_name, type_tok.text, block)
} else {
p.symbols.define_func(name_tok.text, type_tok.text, block)
}
return FuncDecl {
name: name_tok.text
ret_type: ret_type
block: block
params: params
class_name: class_name
}
}