referencing and methods
This commit is contained in:
188
parser.v
188
parser.v
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user