simplify and improve pratt

pull/3354/head
Alexander Medvednikov 2020-01-06 16:13:12 +01:00 committed by GitHub
parent 025efcb731
commit b815878d60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 861 additions and 518 deletions

View File

@ -38,7 +38,7 @@ fn expr1() Expr {
//return BinExpr{}
}
fn expr2() Expr {
fn expr() Expr {
return BinExpr{}
}

View File

@ -8,11 +8,12 @@ import (
v.types
)
pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral |
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr
pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral |
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr | AssignExpr | PrefixExpr
pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt |
pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt |
ForStmt | StructDecl
// | IncDecStmt k
// Stand-alone expression in a statement list.
pub struct ExprStmt {
pub:
@ -71,8 +72,8 @@ pub:
pub struct StructInit {
pub:
ti types.TypeIdent
// typ types.Type
// typ types.TypeIdent
ti types.TypeIdent
fields []string
exprs []Expr
}
@ -80,26 +81,23 @@ pub:
// import statement
pub struct Import {
pub:
mods []string
mods map[string]string // alias -> module
// expr Expr
// imports map[string]string
}
pub struct Arg {
pub:
ti types.TypeIdent
// typ types.Type
name string
}
pub struct FnDecl {
pub:
name string
stmts []Stmt
ti types.TypeIdent
// typ types.Type
args []Arg
is_pub bool
name string
stmts []Stmt
ti types.TypeIdent
args []Arg
is_pub bool
receiver Field
}
@ -137,7 +135,6 @@ pub:
name string
expr Expr
ti types.TypeIdent
// typ types.Type
}
pub struct File {
@ -159,9 +156,9 @@ pub:
// op BinaryOp
op token.Kind
left Expr
// left_type Type
// left_ti types.TypeIdent
right Expr
// right_type Type
// right_ti types.TypeIdent
}
pub struct UnaryExpr {
@ -172,6 +169,18 @@ pub:
left Expr
}
pub struct PostfixExpr {
pub:
op token.Kind
expr Expr
}
pub struct PrefixExpr {
pub:
op token.Kind
right Expr
}
pub struct IfExpr {
pub:
tok_kind token.Kind
@ -179,7 +188,6 @@ pub:
stmts []Stmt
else_stmts []Stmt
ti types.TypeIdent
// typ types.Type
left Expr // `a` in `a := if ...`
}
@ -202,11 +210,17 @@ pub:
op token.Kind
}
pub struct AssignExpr {
pub:
left Expr
val Expr
op token.Kind
}
pub struct ArrayInit {
pub:
exprs []Expr
ti types.TypeIdent
// typ types.Type
}
// string representaiton of expr

View File

@ -14,6 +14,7 @@ struct Gen {
}
pub fn cgen(files []ast.File, table &table.Table) string {
println('start cgen')
mut g := Gen{
out: strings.new_builder(100)
definitions: strings.new_builder(100)
@ -39,25 +40,32 @@ pub fn (g mut Gen) writeln(s string) {
}
fn (g mut Gen) stmt(node ast.Stmt) {
// println('cgen.stmt()')
// g.writeln('//// stmt start')
match node {
ast.Import {
}
/*
ast.AssignStmt {
g.expr(it.left)
g.write(' $it.op.str() ')
g.expr(it.right)
g.writeln(';')
}
*/
ast.FnDecl {
is_main := it.name == 'main'
if is_main {
g.write('int ${it.name}(')
}
else {
g.write('$it.ti.type_name ${it.name}(')
g.definitions.write('$it.ti.type_name ${it.name}(')
g.write('$it.ti.name ${it.name}(')
g.definitions.write('$it.ti.name ${it.name}(')
}
for arg in it.args {
g.write(arg.ti.type_name + ' ' + arg.name)
g.definitions.write(arg.ti.type_name + ' ' + arg.name)
g.write(arg.ti.name + ' ' + arg.name)
g.definitions.write(arg.ti.name + ' ' + arg.name)
}
g.writeln(') { ')
if !is_main {
@ -77,7 +85,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.VarDecl {
g.write('$it.ti.type_name $it.name = ')
g.write('$it.ti.name $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
@ -97,7 +105,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.StructDecl {
g.writeln('typedef struct {')
for field in it.fields {
g.writeln('\t$field.ti.type_name $field.name;')
g.writeln('\t$field.ti.name $field.name;')
}
g.writeln('} $it.name;')
}
@ -120,12 +128,21 @@ fn (g mut Gen) stmt(node ast.Stmt) {
fn (g mut Gen) expr(node ast.Expr) {
// println('cgen expr()')
match node {
ast.AssignExpr {
g.expr(it.left)
g.write(' $it.op.str() ')
g.expr(it.val)
}
ast.IntegerLiteral {
g.write(it.val.str())
}
ast.FloatLiteral {
g.write(it.val)
}
ast.PostfixExpr {
g.expr(it.expr)
g.write(it.op.str())
}
ast.UnaryExpr {
// probably not :D
if it.op in [.inc, .dec] {
@ -140,6 +157,10 @@ fn (g mut Gen) expr(node ast.Expr) {
ast.StringLiteral {
g.write('tos3("$it.val")')
}
ast.PrefixExpr {
g.write(it.op.str())
g.expr(it.right)
}
ast.BinaryExpr {
g.expr(it.left)
if it.op == .dot {
@ -153,7 +174,7 @@ fn (g mut Gen) expr(node ast.Expr) {
}
// `user := User{name: 'Bob'}`
ast.StructInit {
g.writeln('($it.ti.type_name){')
g.writeln('($it.ti.name){')
for i, field in it.fields {
g.write('\t.$field = ')
g.expr(it.exprs[i])
@ -172,7 +193,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(')')
}
ast.ArrayInit {
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t')
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.name), {\t')
for expr in it.exprs {
g.expr(expr)
g.write(', ')
@ -199,16 +220,16 @@ fn (g mut Gen) expr(node ast.Expr) {
// If expression? Assign the value to a temp var.
// Previously ?: was used, but it's too unreliable.
mut tmp := ''
if it.ti.type_kind != ._void {
if it.ti.kind != ._void {
tmp = g.table.new_tmp_var()
// g.writeln('$it.typ.name $tmp;')
// g.writeln('$it.ti.name $tmp;')
}
g.write('if (')
g.expr(it.cond)
g.writeln(') {')
for i, stmt in it.stmts {
// Assign ret value
if i == it.stmts.len - 1 && it.ti.type_kind != ._void {
if i == it.stmts.len - 1 && it.ti.kind != ._void {
// g.writeln('$tmp =')
println(1)
}

View File

@ -9,7 +9,7 @@ import (
)
const (
nr_tests = 2
nr_tests = 3
)
fn test_c_files() {

View File

@ -40,9 +40,9 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.FnDecl {
g.write('/** @return { $it.ti.type_name } **/\nfunction ${it.name}(')
g.write('/** @return { $it.ti.name } **/\nfunction ${it.name}(')
for arg in it.args {
g.write(' /** @type { arg.ti.type_name } **/ $arg.name')
g.write(' /** @type { arg.ti.name } **/ $arg.name')
}
g.writeln(') { ')
for stmt in it.stmts {
@ -56,7 +56,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.VarDecl {
g.write('var /* $it.ti.type_name */ $it.name = ')
g.write('var /* $it.ti.name */ $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
@ -72,7 +72,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
ast.StructDecl {
// g.writeln('typedef struct {')
// for field in it.fields {
// g.writeln('\t$field.ti.type_name $field.name;')
// g.writeln('\t$field.ti.name $field.name;')
// }
g.writeln('var $it.name = function() {};')
}
@ -115,7 +115,7 @@ fn (g mut JsGen) expr(node ast.Expr) {
}
// `user := User{name: 'Bob'}`
ast.StructInit {
g.writeln('/*$it.ti.type_name*/{')
g.writeln('/*$it.ti.name*/{')
for i, field in it.fields {
g.write('\t$field : ')
g.expr(it.exprs[i])

View File

@ -10,9 +10,10 @@ typedef struct {
int main() {
int a = 10;
a++;
int c = -a;
int negative = -a;
a == 1;
foo(3);
int ak = 10;
return 0;
}
@ -37,4 +38,8 @@ void myuser() {
int boo = 2;
int boo2 = boo + 1;
bool b = age > 0;
bool b2 = user.age > 0;
}
void variadic(variadic_int a) {
}

View File

@ -1,13 +1,19 @@
import moda
import modb as mb
struct User {
age int
}
// lol
fn main() {
a := 10
a++
c := -a
negative := -a
a == 1
foo(3)
ak := 10
}
/*
user := User{}
user.age = 10
@ -16,7 +22,6 @@ fn main() {
}
*/
}
fn foo(a int) {
n := get_int2()
@ -37,5 +42,8 @@ fn myuser() {
boo := 2
boo2 := boo+1
b := age > 0
//b2 := user.age > 0
b2 := user.age > 0
}
fn variadic(a ...int) {
}

View File

@ -0,0 +1,13 @@
typedef struct {
int age;
string name;
} User;
int main() {
User user = (User){
};
user.age = 10;
user.age++;
user.name = tos3("bob");
return 0;
}

View File

@ -0,0 +1,11 @@
struct User {
age int
name string
}
fn main() {
user := User{}
user.age = 10
user.age++
user.name = 'bob'
}

View File

@ -337,7 +337,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln(';')
}
ast.VarDecl {
g.write('$it.ti.type_name $it.name = ')
g.write('$it.ti.name $it.name = ')
g.expr(it.expr)
g.writeln(';')
}
@ -354,7 +354,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.StructDecl {
g.writeln('typedef struct {')
for field in it.fields {
g.writeln('\t$field.ti.type_name $field.name;')
g.writeln('\t$field.ti.name $field.name;')
}
g.writeln('} $it.name;')
}
@ -400,7 +400,7 @@ fn (g mut Gen) expr(node ast.Expr) {
}
// `user := User{name: 'Bob'}`
ast.StructInit {
g.writeln('($it.ti.type_name){')
g.writeln('($it.ti.name){')
for i, field in it.fields {
g.write('\t.$field = ')
g.expr(it.exprs[i])
@ -426,7 +426,7 @@ fn (g mut Gen) expr(node ast.Expr) {
}
ast.ArrayInit {
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t')
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.name), {\t')
for expr in it.exprs {
g.expr(expr)
g.write(', ')

View File

@ -0,0 +1,162 @@
module parser
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
import v.types
pub fn (p mut Parser) parse_array_ti(nr_muls int) types.TypeIdent {
p.check(.lsbr)
// fixed array
if p.tok.kind == .number {
size := p.tok.lit.int()
p.check(.rsbr)
elem_ti := p.parse_ti()
idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1)
return types.new_ti(._array_fixed, name, idx, nr_muls)
}
// array
elem_ti := p.parse_ti()
mut nr_dims := 1
for p.tok.kind == .lsbr {
p.check(.lsbr)
p.next()
nr_dims++
}
p.check(.rsbr)
idx,name := p.table.find_or_register_array(&elem_ti, nr_dims)
return types.new_ti(._array, name, idx, nr_muls)
}
pub fn (p mut Parser) parse_map_ti(nr_muls int) types.TypeIdent {
p.next()
p.check(.lsbr)
key_ti := p.parse_ti()
p.check(.rsbr)
value_ti := p.parse_ti()
idx,name := p.table.find_or_register_map(&key_ti, &value_ti)
return types.new_ti(._map, name, idx, nr_muls)
}
pub fn (p mut Parser) parse_multi_return_ti() types.TypeIdent {
p.check(.lpar)
mut mr_tis := []&types.TypeIdent
for {
mr_ti := p.parse_ti()
mr_tis << &mr_ti
if p.tok.kind == .comma {
p.check(.comma)
}
else {
break
}
}
p.check(.rpar)
idx,name := p.table.find_or_register_multi_return(mr_tis)
return types.new_ti(._multi_return, name, idx, 0)
}
pub fn (p mut Parser) parse_variadic_ti() types.TypeIdent {
p.check(.ellipsis)
variadic_ti := p.parse_ti()
idx,name := p.table.find_or_register_variadic(&variadic_ti)
return types.new_ti(._variadic, name, idx, 0)
}
pub fn (p mut Parser) parse_ti() types.TypeIdent {
mut nr_muls := 0
for p.tok.kind == .amp {
p.check(.amp)
nr_muls++
}
name := p.tok.lit
match p.tok.kind {
// array
.lsbr {
return p.parse_array_ti(nr_muls)
}
// multiple return
.lpar {
if nr_muls > 0 {
p.error('parse_ti: unexpected `&` before multiple returns')
}
return p.parse_multi_return_ti()
}
// variadic
.ellipsis {
if nr_muls > 0 {
p.error('parse_ti: unexpected `&` before variadic')
}
return p.parse_variadic_ti()
}
else {
defer {
p.next()
}
match name {
// map
'map' {
return p.parse_map_ti(nr_muls)
}
'voidptr' {
return types.new_base_ti(._voidptr, nr_muls)
}
'byteptr' {
return types.new_base_ti(._byteptr, nr_muls)
}
'charptr' {
return types.new_base_ti(._charptr, nr_muls)
}
'i8' {
return types.new_base_ti(._i8, nr_muls)
}
'i16' {
return types.new_base_ti(._i16, nr_muls)
}
'int' {
return types.new_base_ti(._int, nr_muls)
}
'i64' {
return types.new_base_ti(._i64, nr_muls)
}
'byte' {
return types.new_base_ti(._byte, nr_muls)
}
'u16' {
return types.new_base_ti(._u16, nr_muls)
}
'u32' {
return types.new_base_ti(._u32, nr_muls)
}
'u64' {
return types.new_base_ti(._u64, nr_muls)
}
'f32' {
return types.new_base_ti(._f32, nr_muls)
}
'f64' {
return types.new_base_ti(._f64, nr_muls)
}
'string' {
return types.new_base_ti(._string, nr_muls)
}
'char' {
return types.new_base_ti(._char, nr_muls)
}
'bool' {
return types.new_base_ti(._bool, nr_muls)
}
// struct / enum / placeholder
else {
// struct / enum
mut idx := p.table.find_type_idx(name)
// add placeholder
if idx == 0 {
idx = p.table.add_placeholder_type(name)
}
return types.new_ti(._placeholder, name, idx, nr_muls)
}
}
}
}
}

View File

@ -15,14 +15,15 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) {
fn_name := p.check_name()
p.check(.lpar)
mut is_unknown := false
is_unknown = false
mut args := []ast.Expr
mut return_ti := types.new_base_ti(._void, 0)
mut return_ti := types.void_ti
if f := p.table.find_fn(fn_name) {
return_ti = f.return_ti
for i, arg in f.args {
e,ti := p.expr(0)
if !types.check(arg.ti, ti) {
p.error('cannot use type `$ti.type_name` as type `$arg.ti.type_name` in argument to `$fn_name`')
if !types.check(&arg.ti, &ti) {
p.error('cannot use type `$ti.name` as type `$arg.ti.name` in argument to `$fn_name`')
}
args << e
if i < f.args.len - 1 {
@ -49,7 +50,7 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) {
args: args
is_unknown: is_unknown
tok: tok
// typ: return_type
// typ: return_ti
}
if is_unknown {
@ -67,7 +68,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.check(.key_fn)
// Receiver?
mut rec_name := ''
mut rec_ti := types.new_base_ti(._void, 0)
mut rec_ti := types.void_ti
if p.tok.kind == .lpar {
p.next()
rec_name = p.check_name()
@ -113,8 +114,8 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
}
p.check(.rpar)
// Return type
mut ti := types.new_base_ti(._void, 0)
if p.tok.kind in [.amp, .name] {
mut ti := types.void_ti
if p.tok.kind == .name {
ti = p.parse_ti()
p.return_ti = ti
}
@ -145,7 +146,7 @@ pub fn (p &Parser) check_fn_calls() {
return
}
println(f.name)
// println(f.return_type.name)
// println(f.return_ti.name)
// println('IN AST typ=' + call.typ.name)
}
}

View File

@ -13,16 +13,24 @@ import (
os
)
type PrefixParseFn fn()ast.Expr
type InfixParseFn fn(e ast.Expr)ast.Expr
type PostfixParseFn fn()ast.Expr
struct Parser {
scanner &scanner.Scanner
file_name string
scanner &scanner.Scanner
file_name string
mut:
tok token.Token
peek_tok token.Token
tok token.Token
peek_tok token.Token
// vars []string
table &table.Table
return_ti types.TypeIdent
is_c bool
table &table.Table
return_ti types.TypeIdent
is_c bool
//
prefix_parse_fns []PrefixParseFn
}
pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
@ -31,135 +39,13 @@ pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
scanner: s
table: table
}
p.init_parse_fns()
p.read_first_token()
return p.stmt()
}
pub fn (p mut Parser) parse_ti() types.TypeIdent {
defer {
p.next()
}
mut nr_muls := 0
if p.tok.kind == .amp {
p.check(.amp)
nr_muls = 1
}
name := p.tok.lit
if nr_muls > 0 {
println('## POINTER: $name')
}
match name {
'voidptr' {
return types.new_base_ti(._voidptr, nr_muls)
}
'byteptr' {
return types.new_base_ti(._byteptr, nr_muls)
}
'charptr' {
return types.new_base_ti(._charptr, nr_muls)
}
'164' {
return types.new_base_ti(._i16, nr_muls)
}
'int' {
return types.new_base_ti(._int, nr_muls)
}
'i64' {
return types.new_base_ti(._i64, nr_muls)
}
'byte' {
return types.new_base_ti(._byte, nr_muls)
}
'u16' {
return types.new_base_ti(._u16, nr_muls)
}
'u32' {
return types.new_base_ti(._u32, nr_muls)
}
'u64' {
return types.new_base_ti(._u64, nr_muls)
}
'f32' {
return types.new_base_ti(._f32, nr_muls)
}
'f64' {
return types.new_base_ti(._f64, nr_muls)
}
'string' {
return types.new_base_ti(._string, nr_muls)
}
'char' {
return types.new_base_ti(._char, nr_muls)
}
'bool' {
return types.new_base_ti(._bool, nr_muls)
}
else {
// array
if p.tok.kind == .lsbr {
p.check(.lsbr)
// fixed array
if p.tok.kind == .number {
fixed_size := p.tok.lit.int()
p.check(.rsbr)
elem_ti := p.parse_ti()
array_fixed_type := types.ArrayFixed{
name: 'array_fixed_$elem_ti.type_name'
size: fixed_size
elem_type_idx: elem_ti.type_idx
elem_is_ptr: elem_ti.is_ptr()
}
idx := p.table.find_or_register_array_fixed(array_fixed_type)
return types.new_ti(._array_fixed, array_fixed_type.name, idx, nr_muls)
}
p.check(.rsbr)
// array
elem_ti := p.parse_ti()
array_type := types.Array{
name: 'array_$elem_ti.type_name'
elem_type_idx: elem_ti.type_idx
elem_is_ptr: elem_ti.is_ptr()
}
idx := p.table.find_or_register_array(array_type)
return types.new_ti(._array, array_type.name, idx, nr_muls)
}
// map
else if name == 'map' {
p.next()
p.check(.lsbr)
key_ti := p.parse_ti()
p.check(.rsbr)
value_ti := p.parse_ti()
map_type := types.Map{
name: 'map_${key_ti.type_name}_${value_ti.type_name}'
key_type_idx: key_ti.type_idx,
value_type_idx: value_ti.type_idx
}
idx := p.table.find_or_register_map(map_type)
return types.new_ti(._map, map_type.name, idx, nr_muls)
} else {
// struct / enum
mut idx := p.table.find_type_idx(name)
// add placeholder
if idx == 0 {
idx = p.table.add_placeholder_type(name)
}
return types.new_ti(._placeholder, name, idx, nr_muls)
}
// typ := p.table.find_type(p.tok.lit) or {
// // typ := p.table.types[p.tok.lit]
// // if isnil(typ.name.str) || typ.name == '' {
// p.error('undefined type `$p.tok.lit`')
// exit(0)
// }
// println('RET Typ $typ.name')
}
}
}
pub fn parse_file(path string, table &table.Table) ast.File {
println('parse file "$path"')
println('parse_file("$path")')
text := os.read_file(path) or {
panic(err)
}
@ -173,12 +59,11 @@ pub fn parse_file(path string, table &table.Table) ast.File {
for {
// res := s.scan()
if p.tok.kind == .eof {
println('EOF, breaking')
break
}
// println('expr at ' + p.tok.str())
s := p.stmt()
// println(s)
stmts << s // p.stmt()
// println('stmt at ' + p.tok.str())
stmts << p.top_stmt()
}
p.check_fn_calls()
// println('nr stmts = $stmts.len')
@ -196,6 +81,11 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
return files
}
pub fn (p mut Parser) init_parse_fns() {
p.prefix_parse_fns = make(100, 100, sizeof(PrefixParseFn))
// p.prefix_parse_fns[token.Kind.name] = parse_name
}
pub fn (p mut Parser) read_first_token() {
// need to call next() twice to get peek token and current token
p.next()
@ -205,13 +95,14 @@ pub fn (p mut Parser) read_first_token() {
pub fn (p mut Parser) parse_block() []ast.Stmt {
p.check(.lcbr)
mut stmts := []ast.Stmt
for {
// res := s.scan()
if p.tok.kind in [.eof, .rcbr] {
break
if p.tok.kind != .rcbr {
for {
stmts << p.stmt()
// p.warn('after stmt(): tok=$p.tok.str()')
if p.tok.kind in [.eof, .rcbr] {
break
}
}
// println('expr at ' + p.tok.str())
stmts << p.stmt()
}
p.check(.rcbr)
// println('nr exprs in block = $exprs.len')
@ -238,17 +129,7 @@ fn (p mut Parser) check_name() string {
return name
}
pub fn (p mut Parser) stmt() ast.Stmt {
// println('stmt at ' + p.tok.str())
// `x := ...`
if p.tok.kind == .name {
if p.peek_tok.kind == .decl_assign {
return p.var_decl()
}
else if p.peek_tok.is_assign() {
return p.assign_stmt()
}
}
pub fn (p mut Parser) top_stmt() ast.Stmt {
match p.tok.kind {
.key_module {
return p.module_decl()
@ -285,16 +166,30 @@ pub fn (p mut Parser) stmt() ast.Stmt {
.key_struct {
return p.struct_decl()
}
.key_return {
return p.return_stmt()
else {
p.error('bad top level statement')
return ast.Module{} // silence C warning
// exit(0)
}
}
}
pub fn (p mut Parser) stmt() ast.Stmt {
match p.tok.kind {
.key_mut {
return p.var_decl()
}
.key_for {
return p.for_statement()
}
.key_return {
return p.return_stmt()
}
else {
// `x := ...`
if p.tok.kind == .name && p.peek_tok.kind == .decl_assign {
return p.var_decl()
}
expr,ti := p.expr(0)
return ast.ExprStmt{
expr: expr
@ -304,11 +199,24 @@ pub fn (p mut Parser) stmt() ast.Stmt {
}
}
pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr {
op := p.tok.kind
p.next()
val,_ := p.expr(0)
node := ast.AssignExpr{
left: left
op: op
val: val
}
return node
}
/*
pub fn (p mut Parser) assign_stmt() ast.AssignStmt {
name := p.tok.lit
// println('looking for $name')
var := p.table.find_var(name) or {
p.error('unknown variable `$name`')
p.error('assign unknown variable `$name`')
exit(1)
}
if !var.is_mut {
@ -328,6 +236,8 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt {
op: op
}
}
*/
pub fn (p &Parser) error(s string) {
println(term.bold(term.red('$p.file_name:$p.tok.line_nr: $s')))
@ -343,138 +253,137 @@ pub fn (p &Parser) warn(s string) {
println(term.blue('$p.file_name:$p.tok.line_nr: $s'))
}
// Implementation of Pratt Precedence
pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.TypeIdent) {
// println('expr at ' + p.tok.str())
// null denotation (prefix)
pub fn (p mut Parser) name_expr() (ast.Expr,types.TypeIdent) {
mut node := ast.Expr{}
// mut typ := types.void_type
mut ti := types.new_base_ti(._void, 0)
mut ti := types.void_ti
// fn call
if p.peek_tok.kind == .lpar {
x,ti2 := p.call_expr() // TODO `node,typ :=` should work
node = x
ti = ti2
}
// struct init
else if p.peek_tok.kind == .lcbr {
ti = p.parse_ti()
// println('sturct init ti=$ti.name')
p.check(.lcbr)
mut field_names := []string
mut exprs := []ast.Expr
for p.tok.kind != .rcbr {
field_name := p.check_name()
field_names << field_name
p.check(.colon)
// expr,field_type := p.expr(0)
expr,_ := p.expr(0)
// if !types.check( ,field_type
exprs << expr
}
node = ast.StructInit{
ti: ti
exprs: exprs
fields: field_names
}
p.check(.rcbr)
}
else {
// p.warn('name ')
// left := p.parse_ident()
node = ast.Ident{
name: p.tok.lit
}
var := p.table.find_var(p.tok.lit) or {
p.error('name expr unknown variable `$p.tok.lit`')
exit(0)
}
ti = var.ti
p.next()
}
return node,ti
}
pub fn (p mut Parser) expr(precedence int) (ast.Expr,types.TypeIdent) {
mut ti := types.void_ti
mut node := ast.Expr{}
// Prefix
match p.tok.kind {
.name {
/*
sym := p.table.find_symbol(p.tok.lit)
if sym.cat == .function {
return
}
*/
if p.tok.lit == 'C' {
p.is_c = true
println('is c')
p.next()
p.check(.dot)
}
// fn call
if p.peek_tok.kind == .lpar {
x,ti2 := p.call_expr() // TODO `node,typ :=` should work
node = x
ti = ti2
}
// struct init
else if p.peek_tok.kind == .lcbr {
ti = p.parse_ti()
// println('sturct init typ=$typ.name')
p.check(.lcbr)
mut field_names := []string
mut exprs := []ast.Expr
for p.tok.kind != .rcbr {
field_name := p.check_name()
field_names << field_name
p.check(.colon)
// expr,field_type := p.expr(0)
expr,_ := p.expr(0)
// if !types.check( ,field_type
exprs << expr
}
node = ast.StructInit{
ti: ti
exprs: exprs
fields: field_names
}
p.check(.rcbr)
}
else {
// name expr
node = ast.Ident{
name: p.tok.lit
}
var := p.table.find_var(p.tok.lit) or {
p.error('unknown variable `$p.tok.lit`')
exit(0)
}
ti = var.ti
// ///typ = types.int_type
p.next()
}
node,ti = p.name_expr()
}
.lsbr {
node,ti = p.array_init()
.str {
node,ti = p.parse_string_literal()
}
// -1, -a etc
.minus {
node,ti = p.prefix_expr()
}
.key_true, .key_false {
node = ast.BoolLiteral{
val: p.tok.kind == .key_true
}
ti = types.new_base_ti(._bool, 0)
ti = types.bool_ti
p.next()
}
.str {
node,ti = p.parse_string_literal()
}
.number {
node,ti = p.parse_number_literal()
}
.key_if {
node,ti = p.if_expr()
}
.lpar {
p.check(.lpar)
p.next()
node,ti = p.expr(token.lowest_prec)
node,ti = p.expr(0)
p.check(.rpar)
}
.key_if {
node,ti = p.if_expr()
}
.lsbr {
node,ti = p.array_init()
}
else {
if p.tok.is_unary() {
pt := p.tok
p.next()
expr,ti2 := p.expr(token.lowest_prec)
node = ast.UnaryExpr{
left: expr
op: pt.kind
}
ti = ti2
}
else {
p.error('expr(): unknown token ' + p.tok.str() + ' kind=$p.tok.kind')
}
p.error('expr(): bad token `$p.tok.str()`')
}
}
// left binding power
for rbp < p.tok.precedence() {
prev_tok := p.tok
p.next()
// mut t2 := types.Type{}
mut ti2 := types.new_base_ti(._void, 0)
// left denotation (infix / postfix)
if prev_tok.is_right_assoc() && !p.tok.kind in [.plus, .minus] && // think of better way to handle this
!p.peek_tok.kind in [.number, .name] {
// supposed to be only unary, additive handled in left asssoc
mut expr := ast.Expr{}
expr,ti2 = p.expr(prev_tok.precedence() - 1)
node = ast.BinaryExpr{
left: node
op: prev_tok.kind
right: expr
}
// println(t2.name + 'OOO')
if !types.check(&ti, &ti2) {
println('tok: $prev_tok.str()')
p.error('cannot convert `$ti2.type_name` to `$ti.type_name`')
}
// Infix
for precedence < p.tok.precedence() {
if p.tok.kind.is_assign() {
node = p.assign_expr(node)
}
else if prev_tok.is_left_assoc() {
// postfix `.`
if prev_tok.kind == .dot {
p.warn('dot prev_tok = $prev_tok.str() typ=$ti.type_name')
else if p.tok.kind == .dot {
node,ti = p.dot_expr(node)
}
else if p.tok.kind.is_infix() {
node,ti = p.infix_expr(node)
}
else if p.tok.kind in [.inc, .dec] {
node = ast.PostfixExpr{
op: p.tok.kind
expr: node
}
p.next()
return node,ti
}
else {
return node,ti
}
}
return node,ti
}
fn (p mut Parser) prefix_expr() (ast.Expr,types.TypeIdent) {
op := p.tok.kind
p.next()
right,ti := p.expr(1)
mut expr := ast.Expr{}
expr = ast.PrefixExpr{
op: op
right: right
}
return expr,ti
}
fn (p mut Parser) dot_expr(left ast.Expr) (ast.Expr,types.TypeIdent) {
p.next()
field_name := p.check_name()
/*
// p.next()
field := p.check_name()
if !ti.type_kind in [._placeholder, ._struct] {
@ -491,41 +400,36 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.TypeIdent) {
if !ok {
p.error('unknown field `${typ.name}.$field`')
}
node = ast.SelectorExpr{
expr: node
field: field
}
// return node,typ
}
// postfix (`++` | `--`)
else if prev_tok.kind in [.inc, .dec] {
node = ast.UnaryExpr{
left: node
op: prev_tok.kind
}
}
else {
mut expr := ast.Expr{}
expr,ti2 = p.expr(prev_tok.precedence() - 1)
if prev_tok.is_relational() {
// typ = types.bool_type
ti = types.new_base_ti(._bool, 0)
}
else {
ti = ti2
}
// println(ti2.type_name + '222')
node = ast.BinaryExpr{
left: node
op: prev_tok.kind
right: expr
}
}
}
*/
mut node := ast.Expr{}
node = ast.SelectorExpr{
expr: left
field: field_name
}
return node,ti
return node,types.int_ti
}
fn (p mut Parser) infix_expr(left ast.Expr) (ast.Expr,types.TypeIdent) {
op := p.tok.kind
// mut typ := p.
// println('infix op=$op.str()')
precedence := p.tok.precedence()
p.next()
right,mut ti := p.expr(precedence)
if op.is_relational() {
ti = types.bool_ti
}
mut expr := ast.Expr{}
expr = ast.BinaryExpr{
op: op
left: left
right: right
}
return expr,ti
}
// Implementation of Pratt Precedence
[inline]
fn (p &Parser) is_addative() bool {
return p.tok.kind in [.plus, .minus] && p.peek_tok.kind in [.number, .name]
@ -552,8 +456,7 @@ fn (p mut Parser) for_statement() ast.ForStmt {
}
// `for cond {`
cond,ti := p.expr(0)
// if !types.check(types.bool_type, ti) {
if ti.type_kind != ._bool {
if !types.check(types.bool_ti, ti) {
p.error('non-bool used as for condition')
}
stmts := p.parse_block()
@ -566,27 +469,25 @@ fn (p mut Parser) for_statement() ast.ForStmt {
fn (p mut Parser) if_expr() (ast.Expr,types.TypeIdent) {
mut node := ast.Expr{}
p.check(.key_if)
cond,cond_type := p.expr(0)
// if !types.check(types.bool_type, cond_type) {
if cond_type.type_kind != ._bool {
cond,cond_ti := p.expr(0)
// if !types.check(types.bool_ti, cond_ti) {
if cond_ti.kind != ._bool {
p.error('non-bool used as if condition')
}
stmts := p.parse_block()
mut else_stmts := []ast.Stmt
if p.tok.kind == .key_else {
// println('GOT ELSE')
p.check(.key_else)
else_stmts = p.parse_block()
}
// mut typ := types.void_type
mut ti := types.new_base_ti(._void, 0)
mut ti := types.void_ti
// mut left := ast.Expr{}
// If the last statement is an expression, return its type
match stmts[stmts.len - 1] {
ast.ExprStmt {
p.warn('if expr ret $it.ti.type_name')
p.warn('if expr ret $it.ti.name')
ti = it.ti
// return node,it.typ
// return node,it.ti
// left =
}
else {}
@ -608,14 +509,12 @@ fn (p mut Parser) parse_string_literal() (ast.Expr,types.TypeIdent) {
val: p.tok.lit
}
p.next()
// return node,types.string_type
return node, types.new_base_ti(._string, 0)
return node,types.string_ti
}
fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) {
p.check(.lsbr)
// mut val_type := types.void_type
mut val_ti := types.new_base_ti(._void, 0)
mut val_ti := types.void_ti
mut exprs := []ast.Expr
mut i := 0
for p.tok.kind != .rsbr {
@ -625,7 +524,7 @@ fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) {
val_ti = ti
}
else if !types.check(val_ti, ti) {
p.error('expected array element with type `$val_ti.type_name`')
p.error('expected array element with type `$val_ti.name`')
}
exprs << expr
i++
@ -672,8 +571,15 @@ fn (p mut Parser) module_decl() ast.Module {
fn (p mut Parser) import_stmt() ast.Import {
p.check(.key_import)
name := p.check_name()
mut alias := name
if p.tok.kind == .key_as {
p.check(.key_as)
alias = p.check_name()
}
mut mods := map[string]string
mods[alias] = name
return ast.Import{
mods: [name]
mods: mods
}
}
@ -700,14 +606,10 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
}
fields << types.Field{
name: field_name
type_idx: ti.type_idx
type_idx: ti.idx
}
}
p.check(.rcbr)
if name in p.table.type_idxs {
println('placeholder exists: $name')
}
println('about to register: $name')
p.table.register_struct(types.Struct{
name: name
fields: fields
@ -723,7 +625,7 @@ fn (p mut Parser) return_stmt() ast.Return {
p.next()
expr,t := p.expr(0)
if !types.check(p.return_ti, t) {
p.error('cannot use `$t.type_name` as type `$p.return_ti.type_name` in return argument')
p.error('cannot use `$t.name` as type `$p.return_ti.name` in return argument')
}
return ast.Return{
expr: expr
@ -743,22 +645,22 @@ fn (p mut Parser) var_decl() ast.VarDecl {
}
name := p.tok.lit
p.read_first_token()
expr,t := p.expr(token.lowest_prec)
expr,ti := p.expr(token.lowest_prec)
if _ := p.table.find_var(name) {
p.error('redefinition of `$name`')
}
p.table.register_var(table.Var{
name: name
ti: t
ti: ti
is_mut: is_mut
})
// println(p.table.names)
// println('added $name')
// println('added var `$name` with type $t.name')
return ast.VarDecl{
name: name
expr: expr // p.expr(token.lowest_prec)
ti: t
ti: ti
}
}

View File

@ -4,6 +4,7 @@ import (
v.ast
v.gen
v.table
term
)
fn test_parse_file() {
@ -27,23 +28,58 @@ x := 10
println(res)
}
fn test_parse_expr() {
input := [
fn test_one() {
println('\n\ntest_one()')
input := ['a := 10',
// 'a = 20',
'b := -a',
'c := 20',
//
]
expected := 'int a = 10;int b = -a;int c = 20;'
table := &table.Table{}
mut e := []ast.Stmt
for line in input {
e << parse_stmt(line, table)
}
program := ast.File{
stmts: e
}
res := gen.cgen([program], table).replace('\n', '').trim_space()
ok := expected == res
println(res)
assert ok
if !ok {}
// exit(0)
}
fn test_parse_expr() {
input := ['1 == 1',
'2 * 8 + 3',
'a := 3',
'a++',
'b := 4 + 2',
'neg := -a',
'a + a',
'bo := 2 + 3 == 5',
'2 + 1',
'q := 1',
'q + 777',
'2 + 3',
'2+2*4',
// '(2+2)*4',
'x := 10',
'mut a := 12',
'mut aa := 12',
'ab := 10 + 3 * 9',
's := "hi"',
// '1 += 2',
'x = 11',
'a += 10',
'1.2 + 3.4',
'4 + 4',
'1 + 2 * 5',
'-a',
/*
/*
'(2 * 3) / 2',
'3 + (7 * 6)',
@ -52,28 +88,39 @@ fn test_parse_expr() {
'(2) + (17*2-30) * (5)+2 - (8/2)*4', // 8
//'2 + "hi"',
*/
*/
]
expecting := [
//
expecting := ['1 == 1;',
'2 * 8 + 3;',
'int a = 3;',
'a++;',
'int b = 4 + 2;',
'int neg = -a;',
'a + a;',
'bool bo = 2 + 3 == 5;',
'2 + 1;',
'int q = 1;',
'q + 777;',
'2 + 3;',
'2 + 2 * 4;',
// '(2 + 2) * 4',
'int x = 10;',
'int a = 12;',
'int aa = 12;',
'int ab = 10 + 3 * 9;',
'string s = tos3("hi");',
// '1 += 2;',
'x = 11;',
'a += 10;',
'1.2 + 3.4;',
'4 + 4;',
'1 + 2 * 5;',
'-a;',
]
mut e := []ast.Stmt
table := &table.Table{}
for s in input {
// println('\n\nst="$s"')
e << parse_stmt(s, table)
}
program := ast.File{
@ -89,8 +136,13 @@ fn test_parse_expr() {
if line == '' {
continue
}
println('V:"$line" expecting:"${expecting[i]}"')
if line != expecting[i] {
println('V:"$line" expecting:"${expecting[i]}"')
}
assert line == expecting[i]
println(term.green('$i OK'))
println(line)
println('')
i++
if i >= expecting.len {
break

View File

@ -8,8 +8,8 @@ import (
pub struct Table {
// struct_fields map[string][]string
pub mut:
// types map[string]types.Type
types []types.Type
// type_idxs Hashmap
type_idxs map[string]int
local_vars []Var
// fns Hashmap
@ -30,7 +30,7 @@ pub struct Fn {
pub:
name string
args []Var
return_ti types.TypeIdent
return_ti types.TypeIdent
}
pub fn new_table() &Table {
@ -46,7 +46,6 @@ pub fn new_table() &Table {
// save index check, 0 will mean not found
t.types << types.Type{}
t.type_idxs['dymmy_type_at_idx_0'] = 0
return t
}
@ -117,108 +116,6 @@ pub fn (t mut Table) register_fn(new_fn Fn) {
t.fns[new_fn.name] = new_fn
}
pub fn (t mut Table) register_struct(typ types.Struct) int {
mut t2 := types.Type{}
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
ex_type := t.types[existing_idx]
match ex_type {
types.Placeholder {
// override placeholder
println('overriding type placeholder `$it.name` with struct')
t2 = {typ| idx: existing_idx}
t.types[existing_idx] = t2
return existing_idx
}
types.Struct {
return existing_idx
}
else {
panic('cannot register type `$typ.name`, another type with this name exists')
}
}
}
// register
println('registering: $typ.name')
idx := t.types.len
t.type_idxs[typ.name] = idx
t2 = {typ| idx: idx}
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_map(typ types.Map) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_array(typ types.Array) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_array_fixed(typ types.ArrayFixed) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
[inline]
pub fn (t &Table) find_type_idx(name string) int {
return t.type_idxs[name]
}
pub fn (t mut Table) add_placeholder_type(name string) int {
idx := t.types.len
t.type_idxs[name] = t.types.len
mut pt := types.Type{}
pt = types.Placeholder{
idx: idx
name: name
}
println('added placeholder: $name - $idx ')
t.types << pt
return idx
}
pub fn (t &Table) find_type(name string) ?types.Type {
idx := t.type_idxs[name]
if idx > 0 {
return t.types[idx]
}
return none
}
pub fn (t mut Table) new_tmp_var() string {
t.tmp_cnt++

183
vlib/v/table/type.v 100644
View File

@ -0,0 +1,183 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module table
import v.types
[inline]
pub fn (t &Table) find_type_idx(name string) int {
return t.type_idxs[name]
}
[inline]
pub fn (t &Table) find_type(name string) ?types.Type {
idx := t.type_idxs[name]
if idx > 0 {
return t.types[idx]
}
return none
}
pub fn (t mut Table) register_struct(typ types.Struct) int {
mut struct_type := types.Type{}
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
ex_type := t.types[existing_idx]
match ex_type {
types.Placeholder {
// override placeholder
println('overriding type placeholder `$it.name` with struct')
struct_type = {
typ |
idx:existing_idx
}
t.types[existing_idx] = struct_type
return existing_idx
}
types.Struct {
return existing_idx
}
else {
panic('cannot register type `$typ.name`, another type with this name exists')
}
}
}
// register
println('registering: $typ.name')
idx := t.types.len
t.type_idxs[typ.name] = idx
struct_type = {
typ |
idx:idx
}
t.types << struct_type
return idx
}
pub fn (t mut Table) find_or_register_map(key_ti &types.TypeIdent, value_ti &types.TypeIdent) (int,string) {
name := 'map_${key_ti.name}_${value_ti.name}'
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
}
// register
idx := t.types.len
mut map_type := types.Type{}
map_type = types.Map{
name: name
key_type_idx: key_ti.idx
value_type_idx: value_ti.idx
}
t.type_idxs[name] = idx
t.types << map_type
return idx,name
}
pub fn (t mut Table) find_or_register_array(elem_ti &types.TypeIdent, nr_dims int) (int,string) {
name := 'array_${elem_ti.name}_${nr_dims}d'
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
}
// register
idx := t.types.len
mut array_type := types.Type{}
array_type = types.Array{
idx: idx
name: name
elem_type_idx: elem_ti.idx
elem_is_ptr: elem_ti.is_ptr()
nr_dims: nr_dims
}
t.type_idxs[name] = idx
t.types << array_type
return idx,name
}
pub fn (t mut Table) find_or_register_array_fixed(elem_ti &types.TypeIdent, size int, nr_dims int) (int,string) {
name := 'array_fixed_${elem_ti.name}_${size}_${nr_dims}d'
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
}
// register
idx := t.types.len
mut array_fixed_type := types.Type{}
array_fixed_type = types.ArrayFixed{
idx: idx
name: name
elem_type_idx: elem_ti.idx
elem_is_ptr: elem_ti.is_ptr()
size: size
nr_dims: nr_dims
}
t.type_idxs[name] = idx
t.types << array_fixed_type
return idx,name
}
pub fn (t mut Table) find_or_register_multi_return(mr_tis []&types.TypeIdent) (int,string) {
mut name := 'multi_return'
mut mr_type_kinds := []types.Kind
mut mr_type_idxs := []int
for mr_ti in mr_tis {
name += '_$mr_ti.name'
mr_type_kinds << mr_ti.kind
mr_type_idxs << mr_ti.idx
}
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
}
// register
idx := t.types.len
mut mr_type := types.Type{}
mr_type = types.MultiReturn{
idx: idx
name: name
type_kinds: mr_type_kinds
type_idxs: mr_type_idxs
}
t.type_idxs[name] = idx
t.types << mr_type
return idx,name
}
pub fn (t mut Table) find_or_register_variadic(variadic_ti &types.TypeIdent) (int,string) {
name := 'variadic_$variadic_ti.name'
// existing
existing_idx := t.type_idxs[name]
if existing_idx > 0 {
return existing_idx,name
}
// register
idx := t.types.len
mut variadic_type := types.Type{}
variadic_type = types.Variadic{
idx: idx
type_kind: variadic_ti.kind
type_idx: variadic_ti.idx
}
t.type_idxs[name] = idx
t.types << variadic_type
return idx,name
}
pub fn (t mut Table) add_placeholder_type(name string) int {
idx := t.types.len
t.type_idxs[name] = t.types.len
mut pt := types.Type{}
pt = types.Placeholder{
idx: idx
name: name
}
println('added placeholder: $name - $idx ')
t.types << pt
return idx
}

View File

@ -267,8 +267,8 @@ pub fn is_decl(t Kind) bool {
return t in [.key_enum, .key_interface, .key_fn, .key_struct, .key_type, .key_const, .key_import_const, .key_pub, .eof]
}
pub fn (t Token) is_assign() bool {
return t.kind in assign_tokens
pub fn (t Kind) is_assign() bool {
return t in assign_tokens
}
fn (t []Kind) contains(val Kind) bool {
@ -308,7 +308,54 @@ pub const (
lowest_prec = 0
highest_prec = 8
)
// Precedence returns a tokens precedence if defined, otherwise lowest_prec
pub enum Precedence {
lowest
cond // OR or AND
assign // =
eq // == or !=
less_greater // > or <
sum // + or -
product // * or /
mod // %
prefix // -X or !X
call // func(X) or foo.method(X)
index // array[index], map[key]
}
pub fn build_precedences() []Precedence {
mut p := []Precedence
p = make(100, 100, sizeof(Precedence))
p[Kind.assign] = .assign
p[Kind.eq] = .eq
p[Kind.ne] = .eq
p[Kind.lt] = .less_greater
p[Kind.gt] = .less_greater
p[Kind.le] = .less_greater
p[Kind.ge] = .less_greater
p[Kind.plus] = .sum
p[Kind.plus_assign] = .sum
p[Kind.minus] = .sum
p[Kind.minus_assign] = .sum
p[Kind.div] = .product
p[Kind.div_assign] = .product
p[Kind.mul] = .product
p[Kind.mult_assign] = .product
p[Kind.mod] = .mod
p[Kind.and] = .cond
p[Kind.logical_or] = .cond
p[Kind.lpar] = .call
p[Kind.dot] = .call
p[Kind.lsbr] = .index
return p
}
const (
precedences = build_precedences()
// int(Kind.assign): Precedence.assign
// }
)
// precedence returns a tokens precedence if defined, otherwise lowest_prec
pub fn (tok Token) precedence() int {
match tok.kind {
.dot {
@ -316,6 +363,7 @@ pub fn (tok Token) precedence() int {
}
// `++` | `--`
.inc, .dec {
// return 0
return 7
}
// `*` | `/` | `%` | `<<` | `>>` | `&`
@ -335,7 +383,7 @@ pub fn (tok Token) precedence() int {
return 3
}
// `||`
.logical_or {
.logical_or, .assign, .plus_assign, .minus_assign, .div_assign, .mult_assign {
return 2
}
// /.plus_assign {
@ -366,7 +414,7 @@ pub fn (tok Token) is_left_assoc() bool {
return tok.kind in [
// `.`
.dot,
// `+` | `-`
// `+` | `-`
.plus, .minus, // additive
// .number,
// `++` | `--`
@ -396,8 +444,12 @@ pub fn (tok Token) is_right_assoc() bool {
.and_assign, .xor_assign, .or_assign]
}
pub fn (tok Token) is_relational() bool {
return tok.kind in [
pub fn (tok Kind) is_relational() bool {
return tok in [
// `<` | `<=` | `>` | `>=`
.lt, .le, .gt, .ge, .eq, .ne]
}
pub fn (kind Kind) is_infix() bool {
return kind in [.plus, .minus, .mod, .mul, .div, .eq, .ne, .gt, .lt, .ge, .le, .logical_or, .and, .dot]
}

View File

@ -34,27 +34,27 @@ pub enum Kind {
pub struct TypeIdent {
pub:
type_idx int
type_kind Kind
type_name string
idx int
kind Kind
name string
nr_muls int
}
[inline]
pub fn new_ti(type_kind Kind, type_name string, type_idx int, nr_muls int) TypeIdent {
pub fn new_ti(kind Kind, name string, idx int, nr_muls int) TypeIdent {
return TypeIdent{
type_idx: type_idx
type_kind: type_kind
type_name: type_name
idx: idx
kind: kind
name: name
nr_muls: nr_muls
}
}
[inline]
pub fn new_base_ti(type_kind Kind, nr_muls int) TypeIdent {
pub fn new_base_ti(kind Kind, nr_muls int) TypeIdent {
return TypeIdent{
type_kind: type_kind
type_name: type_kind.str()
kind: kind
name: kind.str()
nr_muls: nr_muls
}
}
@ -66,12 +66,12 @@ pub fn (ti &TypeIdent) is_ptr() bool {
[inline]
pub fn (ti &TypeIdent) is_int() bool {
return ti.type_kind in [._i8, ._i16, ._int, ._i64, ._byte, ._u16, ._u32, ._u64]
return ti.kind in [._i8, ._i16, ._int, ._i64, ._byte, ._u16, ._u32, ._u64]
}
[inline]
pub fn (ti &TypeIdent) is_float() bool {
return ti.type_kind in [._f32, ._f64]
return ti.kind in [._f32, ._f64]
}
[inline]
@ -80,18 +80,18 @@ pub fn (ti &TypeIdent) is_number() bool {
}
pub fn (ti &TypeIdent) str() string {
return '$ti.type_kind.str() $ti.type_idx: $ti.type_name ($ti.nr_muls)'
return '$ti.kind.str() $ti.idx: $ti.name ($ti.nr_muls)'
}
pub fn check(got, expected &TypeIdent) bool {
if got.type_idx != expected.type_idx {
if got.idx != expected.idx {
return false
}
return true
}
pub fn (t Kind) str() string {
t_str := match t {
pub fn (k Kind) str() string {
k_str := match k {
._placeholder {
'placeholder'
}
@ -168,7 +168,18 @@ pub fn (t Kind) str() string {
'unknown'
}
}
return t_str
return k_str
}
pub fn (kinds []Kind) str() string {
mut kinds_str := ''
for i, k in kinds {
kinds_str += k.str()
if i < kinds.len-1 {
kinds_str += '_'
}
}
return kinds_str
}
pub type Type = Placeholder | Void | Voidptr | Charptr | Byteptr | Const | Enum | Struct |
@ -179,7 +190,7 @@ pub struct Placeholder {
pub:
idx int
name string
kind Kind
// kind Kind
}
pub struct Void {}
@ -250,6 +261,7 @@ pub:
elem_type_kind Kind
elem_type_idx int
elem_is_ptr bool
nr_dims int
size int
}
@ -265,14 +277,17 @@ pub:
pub struct MultiReturn {
pub:
elem_type_kinds []Kind
elem_type_idxs []int
idx int
name string
type_kinds []Kind
type_idxs []int
}
pub struct Variadic {
pub:
elem_type_kind Kind
elem_type_idx int
idx int
type_kind Kind
type_idx int
}
pub fn (t Void) str() string { return 'void' }
@ -290,8 +305,8 @@ pub fn (t Byte) str() string { return 'byte' }
pub fn (t Array) str() string { return t.name }
pub fn (t ArrayFixed) str() string { return t.name }
pub fn (t Map) str() string { return t.name }
pub fn (t MultiReturn) str() string { return 'multi_return_$t.elem_type_kinds.str()' }
pub fn (t Variadic) str() string { return 'variadic_$t.elem_type_kind.str()' }
pub fn (t MultiReturn) str() string { return t.name }
pub fn (t Variadic) str() string { return 'variadic_$t.type_kind.str()' }
pub const (
void_type = Void{}
@ -312,3 +327,10 @@ pub const (
char_type = Char{}
bool_type = Bool{}
)
pub const (
void_ti = new_base_ti(._void, 0)
int_ti = new_base_ti(._int, 0)
string_ti = new_base_ti(._string, 0)
bool_ti = new_base_ti(._bool, 0)
)