referencing and methods
This commit is contained in:
50
README.md
50
README.md
@@ -114,6 +114,40 @@ this is my string 17
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### References
|
||||||
|
|
||||||
|
One's counterpart to C's pointers are references, which behave the exact same way.
|
||||||
|
The main difference is in how you reference/dereference a variable. We all know C's
|
||||||
|
referencing and dereferencing operators cause some confusion when first learning the language,
|
||||||
|
and to prevent this, One has designated `ref` and `deref` keywords that are meant to be used like
|
||||||
|
functions. Here's an example:
|
||||||
|
|
||||||
|
```
|
||||||
|
let x int = 6;
|
||||||
|
let ref_to_x ref(int) = ref(x);
|
||||||
|
let y int = deref(ref_to_x) # same as y = x
|
||||||
|
```
|
||||||
|
|
||||||
|
References to objects are again quite similar to C, with the only real difference being
|
||||||
|
the access to an object's members. in One, you an access members of an object or of a
|
||||||
|
reference to an object with the `.` notation. But you cannot access the members if the
|
||||||
|
reference nesting goes further. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
let u User = User{17} #user has age 17
|
||||||
|
print(u.age) # outputs 17
|
||||||
|
|
||||||
|
let ref_to_u ref(User) = ref(u)
|
||||||
|
print(ref_to_u.age) # outputs 17
|
||||||
|
|
||||||
|
let nested_ref ref(ref(User)) = ref(ref_to_u)
|
||||||
|
print(nested_ref.age) # not valid
|
||||||
|
```
|
||||||
|
|
||||||
|
Right now, in error messages, it's likely you will still find references marked as `*`s, such as `int*`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
|
|
||||||
Functions in One are very similar to what you see in languages such as go.
|
Functions in One are very similar to what you see in languages such as go.
|
||||||
@@ -181,6 +215,22 @@ fn change_values(u User) {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
Defining a method is very similar to declaring a function. You just have to add the name
|
||||||
|
of the class between parentheses before the function name.
|
||||||
|
|
||||||
|
```
|
||||||
|
fn (User) age() void {
|
||||||
|
this.age++
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
as you can see, a variable called `this` is automatically declared in methods and is always
|
||||||
|
of type `ref` of the class, in this case `ref(User)`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Print
|
### Print
|
||||||
|
|
||||||
Printing is still a work in progress feature, but right now you can print any primitive and non-primitive type.
|
Printing is still a work in progress feature, but right now you can print any primitive and non-primitive type.
|
||||||
|
|||||||
64
generator.v
64
generator.v
@@ -14,18 +14,24 @@ fn mangle_var(name string) string {
|
|||||||
return 'one_var_${name}'
|
return 'one_var_${name}'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mangle_func(name string) string {
|
fn mangle_func(name string, class_name ?string) string {
|
||||||
if name == 'main' {return 'main'}
|
if name == 'main' {return 'main'}
|
||||||
return 'one_func_${name}'
|
mut mangled_name := 'one_func_${name}'
|
||||||
|
if class_name != none {
|
||||||
|
mangled_name += '_${class_name}'
|
||||||
|
}
|
||||||
|
return mangled_name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mangle_struct(name string) string {
|
fn mangle_struct(name string) string {
|
||||||
return 'one_class_${name}_'
|
return 'one_class_${name}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_type_format(type string) string {
|
fn get_type_format(type string) string {
|
||||||
dump(type)
|
if type.contains('*') {
|
||||||
|
return 'p'
|
||||||
|
}
|
||||||
return match type {
|
return match type {
|
||||||
'int', 'bool' {'d'}
|
'int', 'bool' {'d'}
|
||||||
'real' {'f'}
|
'real' {'f'}
|
||||||
@@ -45,17 +51,21 @@ fn (mut g Generator) get_print_label(expr Expr) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Generator) get_c_type(typ string) string {
|
fn (mut g Generator) get_c_type(typ string) string {
|
||||||
return match typ {
|
astkcount := typ.count('*')
|
||||||
|
clean := typ.replace('*', '')
|
||||||
|
return match clean {
|
||||||
'real' {'float'}
|
'real' {'float'}
|
||||||
'int' {'int32_t'}
|
'int' {'int32_t'}
|
||||||
'string' {'OneString'}
|
'string' {'OneString'}
|
||||||
else {typ}
|
else {clean}
|
||||||
}
|
} + '*'.repeat(astkcount)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Generator) mangle_if_class(name string) string {
|
fn (mut g Generator) mangle_if_class(name string) string {
|
||||||
if g.symbols.lookup_class(name) != none {
|
astkcount := name.count('*')
|
||||||
return 'struct ${mangle_struct(name)}'
|
noptr := name.replace('*', '')
|
||||||
|
if g.symbols.lookup_class(noptr) != none {
|
||||||
|
return 'struct ${mangle_struct(noptr)}' + '*'.repeat(astkcount)
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
@@ -119,7 +129,7 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
|
|||||||
}
|
}
|
||||||
FuncDecl {
|
FuncDecl {
|
||||||
c_type := g.mangle_if_class(g.get_c_type(stmt.ret_type))
|
c_type := g.mangle_if_class(g.get_c_type(stmt.ret_type))
|
||||||
g.out.write_string('${c_type} ${mangle_func(stmt.name)}(')
|
g.out.write_string('${c_type} ${mangle_func(stmt.name, stmt.class_name)}(')
|
||||||
for param in stmt.params {
|
for param in stmt.params {
|
||||||
g.gen_stmt(param)
|
g.gen_stmt(param)
|
||||||
if param != stmt.params[stmt.params.len-1]{
|
if param != stmt.params[stmt.params.len-1]{
|
||||||
@@ -170,6 +180,16 @@ fn (mut g Generator) gen_stmt(stmt Stmt) {
|
|||||||
|
|
||||||
fn (mut g Generator) gen_expr(expr Expr) {
|
fn (mut g Generator) gen_expr(expr Expr) {
|
||||||
match expr {
|
match expr {
|
||||||
|
RefExpr {
|
||||||
|
g.out.write_string('(&')
|
||||||
|
g.gen_expr(expr.expr)
|
||||||
|
g.out.write_string(')')
|
||||||
|
}
|
||||||
|
DerefExpr {
|
||||||
|
g.out.write_string('(*')
|
||||||
|
g.gen_expr(expr.expr)
|
||||||
|
g.out.write_string(')')
|
||||||
|
}
|
||||||
RealLiteral {
|
RealLiteral {
|
||||||
g.out.write_string(expr.val.str())
|
g.out.write_string(expr.val.str())
|
||||||
}
|
}
|
||||||
@@ -243,7 +263,22 @@ fn (mut g Generator) gen_expr(expr Expr) {
|
|||||||
g.out.write_string(')')
|
g.out.write_string(')')
|
||||||
}
|
}
|
||||||
FnCall {
|
FnCall {
|
||||||
g.out.write_string('${mangle_func(expr.name)}(')
|
g.out.write_string('${mangle_func(expr.name, none)}(')
|
||||||
|
for arg in expr.args {
|
||||||
|
g.gen_expr(arg)
|
||||||
|
if arg != expr.args[expr.args.len-1]{
|
||||||
|
g.out.write_string(', ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.out.write_string(')')
|
||||||
|
}
|
||||||
|
MethodCall {
|
||||||
|
g.out.write_string('${mangle_func(expr.method, expr.from_type)}(')
|
||||||
|
g.out.write_string('&')
|
||||||
|
g.gen_expr(expr.from)
|
||||||
|
if expr.args.len > 0 {
|
||||||
|
g.out.write_string(', ')
|
||||||
|
}
|
||||||
for arg in expr.args {
|
for arg in expr.args {
|
||||||
g.gen_expr(arg)
|
g.gen_expr(arg)
|
||||||
if arg != expr.args[expr.args.len-1]{
|
if arg != expr.args[expr.args.len-1]{
|
||||||
@@ -268,7 +303,12 @@ fn (mut g Generator) gen_expr(expr Expr) {
|
|||||||
}
|
}
|
||||||
MemberAccess {
|
MemberAccess {
|
||||||
g.gen_expr(expr.from)
|
g.gen_expr(expr.from)
|
||||||
g.out.write_string('.${expr.member}')
|
match expr.from_type.count('*') {
|
||||||
|
0 {g.out.write_string('.')}
|
||||||
|
1 {g.out.write_string('->')}
|
||||||
|
else {panic("Tried accessing member from an object of type ${expr.from_type}")}
|
||||||
|
}
|
||||||
|
g.out.write_string('${expr.member}')
|
||||||
}
|
}
|
||||||
else {panic("Unimplemented expression")}
|
else {panic("Unimplemented expression")}
|
||||||
}
|
}
|
||||||
|
|||||||
6
lexer.v
6
lexer.v
@@ -16,6 +16,8 @@ enum TokenType as u8 {
|
|||||||
kw_return
|
kw_return
|
||||||
kw_print
|
kw_print
|
||||||
kw_class
|
kw_class
|
||||||
|
kw_ref
|
||||||
|
kw_deref
|
||||||
integer
|
integer
|
||||||
real
|
real
|
||||||
boolean
|
boolean
|
||||||
@@ -126,6 +128,8 @@ fn toktype_from_kw(kw string) TokenType {
|
|||||||
'print' {.kw_print}
|
'print' {.kw_print}
|
||||||
'class' {.kw_class}
|
'class' {.kw_class}
|
||||||
'immutable' {.kw_immutable}
|
'immutable' {.kw_immutable}
|
||||||
|
'ref' {.kw_ref}
|
||||||
|
'deref' {.kw_deref}
|
||||||
else {.unknown}
|
else {.unknown}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +149,7 @@ fn is_real(str string) bool {
|
|||||||
|
|
||||||
fn is_keyword(str string) bool {
|
fn is_keyword(str string) bool {
|
||||||
return [
|
return [
|
||||||
"void", "int", "real", "bool", "string", "if", "else", "elif", "while", "break", "fn", "return", "let", "const", "true", "false", "print", "class", "immutable"
|
"void", "int", "real", "bool", "string", "if", "else", "elif", "while", "break", "fn", "return", "let", "const", "true", "false", "print", "class", "immutable", "ref", "deref"
|
||||||
].contains(str)
|
].contains(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
168
parser.v
168
parser.v
@@ -45,6 +45,8 @@ struct FuncSymbolInfo {
|
|||||||
struct ClassSymbolInfo {
|
struct ClassSymbolInfo {
|
||||||
name string
|
name string
|
||||||
members_info map[string]VarSymbolInfo
|
members_info map[string]VarSymbolInfo
|
||||||
|
mut:
|
||||||
|
methods_info map[string]FuncSymbolInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SymbolTable {
|
struct SymbolTable {
|
||||||
@@ -112,6 +114,19 @@ fn (mut s SymbolTable) lookup_class(name string) ?ClassSymbolInfo {
|
|||||||
return none
|
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 {
|
fn (mut s SymbolTable) is_in_global_scope() bool {
|
||||||
return s.variable_scopes.len == 1
|
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 |
|
type Expr = VoidExpr | UnaryExpr | BinaryExpr | IntegerLiteral | RealLiteral | BoolLiteral | StringLiteral |
|
||||||
Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | ClassMember |
|
Variable | TypeExpr | Function | TypeCast | ParenExpr | PrintExpr | FnCall | ClassMember |
|
||||||
ClassInstantiation | MemberAccess
|
ClassInstantiation | MemberAccess | MethodCall | RefExpr | DerefExpr
|
||||||
|
|
||||||
struct VoidExpr {}
|
struct VoidExpr {}
|
||||||
|
|
||||||
|
struct RefExpr {
|
||||||
|
expr Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DerefExpr {
|
||||||
|
expr Expr
|
||||||
|
}
|
||||||
|
|
||||||
struct UnaryExpr {
|
struct UnaryExpr {
|
||||||
expr Expr
|
expr Expr
|
||||||
op string
|
op string
|
||||||
@@ -169,6 +192,7 @@ struct ClassMember {
|
|||||||
|
|
||||||
struct MemberAccess {
|
struct MemberAccess {
|
||||||
from Expr
|
from Expr
|
||||||
|
from_type string
|
||||||
member string
|
member string
|
||||||
member_type string
|
member_type string
|
||||||
}
|
}
|
||||||
@@ -201,6 +225,14 @@ struct FnCall {
|
|||||||
args []Expr
|
args []Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MethodCall {
|
||||||
|
from Expr
|
||||||
|
from_type string
|
||||||
|
method string
|
||||||
|
ret_type string
|
||||||
|
args []Expr
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------- Statements
|
// ------------------------------------------- Statements
|
||||||
|
|
||||||
type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | IfStmt | ElseStmt | ElifStmt | FuncDecl | Param |
|
type Stmt = VarDecl | ExprStmt | ReturnStmt | Block | IfStmt | ElseStmt | ElifStmt | FuncDecl | Param |
|
||||||
@@ -218,6 +250,7 @@ struct FuncDecl {
|
|||||||
params []Param
|
params []Param
|
||||||
ret_type string
|
ret_type string
|
||||||
block Block
|
block Block
|
||||||
|
class_name ?string //if it is a method
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ClassDecl {
|
struct ClassDecl {
|
||||||
@@ -334,6 +367,8 @@ fn (mut p Parser) parse_primary() Expr {
|
|||||||
.lparen {p.parse_paren()}
|
.lparen {p.parse_paren()}
|
||||||
.kw_print {p.parse_print()}
|
.kw_print {p.parse_print()}
|
||||||
.plus, .minus {p.parse_unary_left(token.text)}
|
.plus, .minus {p.parse_unary_left(token.text)}
|
||||||
|
.kw_ref {p.parse_ref()}
|
||||||
|
.kw_deref {p.parse_deref()}
|
||||||
else {parse_error("Unexpected Token")}
|
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()
|
member_tok := p.next()
|
||||||
if member_tok.type != .identifier {parse_error("Expected identifier after member access")}
|
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}")}
|
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
|
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 {
|
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
|
member_name := p.peek().text
|
||||||
p.expect(.identifier)
|
p.expect(.identifier)
|
||||||
|
|
||||||
type_tok := p.peek()
|
type_tok := p.next()
|
||||||
type_name := match type_tok.type {
|
type_name := match type_tok.type {
|
||||||
.type {type_tok.text}
|
.type {type_tok.text}
|
||||||
.identifier {
|
.identifier {
|
||||||
p.expect_ident_is_class(type_tok.text)
|
p.expect_ident_is_class(type_tok.text)
|
||||||
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}")}
|
else{parse_error("Expected type after class member ${member_name} in declaration, got ${p.peek().type}")}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.next()
|
|
||||||
p.expect(.semicolon)
|
p.expect(.semicolon)
|
||||||
return ClassMember{name: member_name, type: type_name is_immutable: is_immut}
|
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)}
|
UnaryExpr {p.get_expr_is_immutable(expr.expr)}
|
||||||
TypeCast {p.get_expr_is_immutable(expr.expr)}
|
TypeCast {p.get_expr_is_immutable(expr.expr)}
|
||||||
MemberAccess {
|
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 := classinfo.members_info[expr.member] or {parse_error("Undefined member ${expr.member}")}
|
||||||
memberinfo.is_immutable
|
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 {
|
fn (mut p Parser) get_expr_type(expr Expr) string {
|
||||||
return match expr {
|
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)}
|
ParenExpr {p.get_expr_type(expr.expr)}
|
||||||
IntegerLiteral {'int'}
|
IntegerLiteral {'int'}
|
||||||
RealLiteral {'real'}
|
RealLiteral {'real'}
|
||||||
@@ -573,6 +670,12 @@ fn (mut p Parser) get_expr_type(expr Expr) string {
|
|||||||
fninfo := p.symbols.lookup_func(expr.name) or {parse_error("Tried to call undefined function ${expr.name}")}
|
fninfo := p.symbols.lookup_func(expr.name) or {parse_error("Tried to call undefined function ${expr.name}")}
|
||||||
fninfo.type
|
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 {
|
MemberAccess {
|
||||||
expr.member_type
|
expr.member_type
|
||||||
}
|
}
|
||||||
@@ -646,6 +749,10 @@ fn (mut p Parser) parse_var_decl(is_const bool) VarDecl {
|
|||||||
p.expect_ident_is_class(type_tok.text)
|
p.expect_ident_is_class(type_tok.text)
|
||||||
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}")}
|
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' {
|
if type_tok.text == 'void' {
|
||||||
parse_error("Cannot declare a variable of type void")
|
parse_error("Cannot declare a variable of type void")
|
||||||
}
|
}
|
||||||
if p.get_expr_type(val) != type_tok.text {
|
if p.get_expr_type(val) != type_name {
|
||||||
parse_error("Mismatch between declared type (${type_tok.text}) and actual type (${p.get_expr_type(val)})")
|
parse_error("Mismatch between declared type (${type_name}) and actual type (${p.get_expr_type(val)})")
|
||||||
}
|
}
|
||||||
p.expect(.semicolon)
|
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 {
|
return VarDecl {
|
||||||
name: name_tok.text
|
name: name_tok.text
|
||||||
@@ -676,7 +783,17 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
|
|||||||
|
|
||||||
p.expect(.kw_fn)
|
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()
|
name_tok := p.next()
|
||||||
|
|
||||||
if name_tok.type != .identifier {
|
if name_tok.type != .identifier {
|
||||||
parse_error("Expected function name after let")
|
parse_error("Expected function name after let")
|
||||||
}
|
}
|
||||||
@@ -689,20 +806,26 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
|
|||||||
|
|
||||||
if p.peek().type != .rparen {
|
if p.peek().type != .rparen {
|
||||||
for {
|
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
|
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 {
|
p_type := match type_tok.type {
|
||||||
.type {type_tok.text}
|
.type {type_tok.text}
|
||||||
.identifier {
|
.identifier {
|
||||||
p.expect_ident_is_class(type_tok.text)
|
p.expect_ident_is_class(type_tok.text)
|
||||||
type_tok.text
|
type_tok.text
|
||||||
}
|
}
|
||||||
|
.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}")}
|
else{parse_error("Expected argument type after name when declaring ${p_name}")}
|
||||||
}
|
}
|
||||||
p.next()
|
|
||||||
params << Param{p_name, p_type}
|
params << Param{p_name, p_type}
|
||||||
p.symbols.define_var(p_name, p_type, false)
|
p.symbols.define_var(p_name, p_type, false)
|
||||||
|
|
||||||
@@ -716,8 +839,6 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
|
|||||||
|
|
||||||
p.expect(.rparen)
|
p.expect(.rparen)
|
||||||
|
|
||||||
p.dump_token()
|
|
||||||
|
|
||||||
type_tok := p.next()
|
type_tok := p.next()
|
||||||
ret_type := match type_tok.type {
|
ret_type := match type_tok.type {
|
||||||
.type {type_tok.text}
|
.type {type_tok.text}
|
||||||
@@ -725,10 +846,20 @@ fn (mut p Parser) parse_func_decl() FuncDecl {
|
|||||||
p.expect_ident_is_class(type_tok.text)
|
p.expect_ident_is_class(type_tok.text)
|
||||||
type_tok.text
|
type_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}")}
|
else{parse_error("Expected function return type after name when declaring ${name_tok.text}")}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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{})
|
p.symbols.define_func(name_tok.text, type_tok.text, Block{})
|
||||||
|
}
|
||||||
|
|
||||||
block := p.parse_block(true)
|
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.variable_scopes.delete_last()
|
||||||
|
|
||||||
|
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)
|
p.symbols.define_func(name_tok.text, type_tok.text, block)
|
||||||
|
}
|
||||||
|
|
||||||
return FuncDecl {
|
return FuncDecl {
|
||||||
name: name_tok.text
|
name: name_tok.text
|
||||||
ret_type: ret_type
|
ret_type: ret_type
|
||||||
block: block
|
block: block
|
||||||
params: params
|
params: params
|
||||||
|
class_name: class_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user