new enum syntax; update the compiler (`p.tok == .name`)

pull/1056/head
Alexander Medvednikov 2019-07-07 22:30:15 +02:00
parent 385f47c0cd
commit 26ef99293d
8 changed files with 835 additions and 834 deletions

View File

@ -45,7 +45,7 @@ fn new_cgen(out_name_c string) *CGen {
} }
fn (g mut CGen) genln(s string) { fn (g mut CGen) genln(s string) {
if g.nogen || g.run == RUN_DECLS { if g.nogen || g.run == .decl {
return return
} }
if g.is_tmp { if g.is_tmp {
@ -61,7 +61,7 @@ fn (g mut CGen) genln(s string) {
} }
fn (g mut CGen) gen(s string) { fn (g mut CGen) gen(s string) {
if g.nogen || g.run == RUN_DECLS { if g.nogen || g.run == .decl {
return return
} }
if g.is_tmp { if g.is_tmp {

View File

@ -114,7 +114,7 @@ fn new_fn(pkg string, is_public bool) *Fn {
// Function signatures are added to the top of the .c file in the first run. // Function signatures are added to the top of the .c file in the first run.
fn (p mut Parser) fn_decl() { fn (p mut Parser) fn_decl() {
p.fgen('fn ') p.fgen('fn ')
is_pub := p.tok == PUB is_pub := p.tok == .key_pub
is_live := p.attr == 'live' && !p.pref.is_so is_live := p.attr == 'live' && !p.pref.is_so
if is_live && !p.pref.is_live { if is_live && !p.pref.is_live {
p.error('run `v -live program.v` if you want to use [live] functions') p.error('run `v -live program.v` if you want to use [live] functions')
@ -124,15 +124,15 @@ fn (p mut Parser) fn_decl() {
} }
p.returns = false p.returns = false
p.next() p.next()
mut f := new_fn(p.pkg, is_pub) mut f := new_fn(p.mod, is_pub)
// Method receiver // Method receiver
mut receiver_typ := '' mut receiver_typ := ''
if p.tok == LPAR { if p.tok == .lpar {
f.is_method = true f.is_method = true
p.check(LPAR) p.check(.lpar)
receiver_name := p.check_name() receiver_name := p.check_name()
is_mut := p.tok == MUT is_mut := p.tok == .key_mut
is_amp := p.tok == AMP is_amp := p.tok == .amp
if is_mut || is_amp { if is_mut || is_amp {
p.check_space(p.tok) p.check_space(p.tok)
} }
@ -142,9 +142,9 @@ fn (p mut Parser) fn_decl() {
p.error('invalid receiver type `$receiver_typ` (`$receiver_typ` is an interface)') p.error('invalid receiver type `$receiver_typ` (`$receiver_typ` is an interface)')
} }
// Don't allow modifying types from a different module // Don't allow modifying types from a different module
if !p.first_run() && !p.builtin_pkg && T.pkg != p.pkg { if !p.first_run() && !p.builtin_pkg && T.mod != p.mod {
println('T.pkg=$T.pkg') println('T.mod=$T.mod')
println('pkg=$p.pkg') println('pkg=$p.mod')
p.error('cannot define new methods on non-local type `$receiver_typ`') p.error('cannot define new methods on non-local type `$receiver_typ`')
} }
// (a *Foo) instead of (a mut Foo) is a common mistake // (a *Foo) instead of (a mut Foo) is a common mistake
@ -156,7 +156,7 @@ fn (p mut Parser) fn_decl() {
if is_mut || is_amp { if is_mut || is_amp {
receiver_typ += '*' receiver_typ += '*'
} }
p.check(RPAR) p.check(.rpar)
p.fspace() p.fspace()
receiver := Var { receiver := Var {
name: receiver_name name: receiver_name
@ -170,7 +170,7 @@ fn (p mut Parser) fn_decl() {
f.args << receiver f.args << receiver
f.register_var(receiver) f.register_var(receiver)
} }
if p.tok == PLUS || p.tok == MINUS || p.tok == MUL { if p.tok == .plus || p.tok == .minus || p.tok == .mul {
f.name = p.tok.str() f.name = p.tok.str()
p.next() p.next()
} }
@ -178,14 +178,14 @@ fn (p mut Parser) fn_decl() {
f.name = p.check_name() f.name = p.check_name()
} }
// C function header def? (fn C.NSMakeRect(int,int,int,int)) // C function header def? (fn C.NSMakeRect(int,int,int,int))
is_c := f.name == 'C' && p.tok == DOT is_c := f.name == 'C' && p.tok == .dot
// Just fn signature? only builtin.v + default build mode // Just fn signature? only builtin.v + default build mode
// is_sig := p.builtin_pkg && p.pref.build_mode == default_mode // is_sig := p.builtin_pkg && p.pref.build_mode == default_mode
// is_sig := p.pref.build_mode == default_mode && (p.builtin_pkg || p.file.contains(LANG_TMP)) // is_sig := p.pref.build_mode == default_mode && (p.builtin_pkg || p.file.contains(LANG_TMP))
is_sig := p.is_sig() is_sig := p.is_sig()
// println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg') // println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg')
if is_c { if is_c {
p.check(DOT) p.check(.dot)
f.name = p.check_name() f.name = p.check_name()
f.is_c = true f.is_c = true
} }
@ -198,7 +198,7 @@ fn (p mut Parser) fn_decl() {
} }
} }
// simple_name := f.name // simple_name := f.name
// println('!SIMPLE=$simple_name') // println('!SIMP.le=$simple_name')
// user.register() => User_register() // user.register() => User_register()
has_receiver := receiver_typ.len > 0 has_receiver := receiver_typ.len > 0
if receiver_typ != '' { if receiver_typ != '' {
@ -206,7 +206,7 @@ fn (p mut Parser) fn_decl() {
} }
// full pkg function name // full pkg function name
// os.exit ==> os__exit() // os.exit ==> os__exit()
if !is_c && !p.builtin_pkg && p.pkg != 'main' && receiver_typ.len == 0 { if !is_c && !p.builtin_pkg && p.mod != 'main' && receiver_typ.len == 0 {
f.name = p.prepend_pkg(f.name) f.name = p.prepend_pkg(f.name)
} }
if p.first_run() && p.table.known_fn(f.name) && receiver_typ.len == 0 { if p.first_run() && p.table.known_fn(f.name) && receiver_typ.len == 0 {
@ -218,42 +218,42 @@ fn (p mut Parser) fn_decl() {
} }
// Generic? // Generic?
mut is_generic := false mut is_generic := false
if p.tok == LT { if p.tok == .lt {
p.next() p.next()
gen_type := p.check_name() gen_type := p.check_name()
if gen_type != 'T' { if gen_type != 'T' {
p.error('only `T` is allowed as a generic type for now') p.error('only `T` is allowed as a generic type for now')
} }
p.check(GT) p.check(.gt)
is_generic = true is_generic = true
} }
// Args (...) // Args (...)
p.fn_args(mut f) p.fn_args(mut f)
// Returns an error? // Returns an error?
if p.tok == NOT { if p.tok == .not {
p.next() p.next()
f.returns_error = true f.returns_error = true
} }
// Returns a type? // Returns a type?
mut typ := 'void' mut typ := 'void'
if p.tok == NAME || p.tok == MUL || p.tok == AMP || p.tok == LSBR || if p.tok == .name || p.tok == .mul || p.tok == .amp || p.tok == .lsbr ||
p.tok == QUESTION { p.tok == .question {
p.fgen(' ') p.fgen(' ')
// TODO In // TODO In
// if p.tok in [ NAME, MUL, AMP, LSBR ] { // if p.tok in [ .name, .mul, .amp, .lsbr ] {
typ = p.get_type() typ = p.get_type()
} }
// Translated C code can have empty functions (just definitions) // Translated C code can have empty functions (just definitions)
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) && is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) &&
(p.tok != LCBR)// || (p.tok == NAME && p.peek() != LCBR)) (p.tok != .lcbr)// || (p.tok == .name && p.peek() != .lcbr))
if is_fn_header { if is_fn_header {
f.is_decl = true f.is_decl = true
// println('GOT fn header $f.name') // println('.key_goT fn header $f.name')
} }
// { required only in normal function declarations // { required only in normal function declarations
if !is_c && !is_sig && !is_fn_header { if !is_c && !is_sig && !is_fn_header {
p.fgen(' ') p.fgen(' ')
p.check(LCBR) p.check(.lcbr)
} }
// Register option ? type // Register option ? type
if typ.starts_with('Option_') { if typ.starts_with('Option_') {
@ -262,7 +262,7 @@ fn (p mut Parser) fn_decl() {
// Register function // Register function
f.typ = typ f.typ = typ
mut str_args := f.str_args(p.table) mut str_args := f.str_args(p.table)
// println('FN DECL $f.name typ=$f.typ str_args="$str_args"') // println('FN .decL $f.name typ=$f.typ str_args="$str_args"')
// Special case for main() args // Special case for main() args
if f.name == 'main' && !has_receiver { if f.name == 'main' && !has_receiver {
if str_args != '' || typ != 'void' { if str_args != '' || typ != 'void' {
@ -305,7 +305,7 @@ fn (p mut Parser) fn_decl() {
// println('fn decl !!!!!!! REG PH $receiver_typ') // println('fn decl !!!!!!! REG PH $receiver_typ')
ttyp := Type { ttyp := Type {
name: receiver_typ.replace('*', '') name: receiver_typ.replace('*', '')
pkg: p.pkg mod: p.mod
is_placeholder: true is_placeholder: true
} }
p.table.register_type2(ttyp) p.table.register_type2(ttyp)
@ -328,7 +328,7 @@ fn (p mut Parser) fn_decl() {
} }
} }
// Live code reloading? Load all fns from .so // Live code reloading? Load all fns from .so
if is_live && p.first_run() && p.pkg == 'main' { if is_live && p.first_run() && p.mod == 'main' {
//println('ADDING SO FN $fn_name_cgen') //println('ADDING SO FN $fn_name_cgen')
p.cgen.so_fns << fn_name_cgen p.cgen.so_fns << fn_name_cgen
fn_name_cgen = '(* $fn_name_cgen )' fn_name_cgen = '(* $fn_name_cgen )'
@ -374,7 +374,7 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
} }
// println('is_c=$is_c name=$f.name') // println('is_c=$is_c name=$f.name')
if is_c || is_sig || is_fn_header { if is_c || is_sig || is_fn_header {
// println('IS SIG RETURNING tok=${p.strtok()}') // println('IS SIG .key_returnING tok=${p.strtok()}')
p.fgenln('\n') p.fgenln('\n')
return return
} }
@ -395,15 +395,15 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
p.error('$f.name must return "$typ"') p.error('$f.name must return "$typ"')
} }
// {} closed correctly? scope_level should be 0 // {} closed correctly? scope_level should be 0
if p.pkg == 'main' { if p.mod == 'main' {
// println(p.cur_fn.scope_level) // println(p.cur_fn.scope_level)
} }
if p.cur_fn.scope_level > 2 { if p.cur_fn.scope_level > 2 {
// p.error('unclosed {') // p.error('unclosed {')
} }
// Make sure all vars in this function are used (only in main for now) // Make sure all vars in this function are used (only in main for now)
// if p.builtin_pkg || p.pkg == 'os' ||p.pkg=='http'{ // if p.builtin_pkg || p.mod == 'os' ||p.mod=='http'{
if p.pkg != 'main' { if p.mod != 'main' {
p.genln('}') p.genln('}')
p.fgenln('\n') p.fgenln('\n')
return return
@ -442,7 +442,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
// println('\nfn_call $f.name is_method=$f.is_method receiver_type=$f.receiver_type') // println('\nfn_call $f.name is_method=$f.is_method receiver_type=$f.receiver_type')
// p.print_tok() // p.print_tok()
mut thread_name := '' mut thread_name := ''
// Normal function => just its name, method => TYPE_FNNAME // Normal function => just its name, method => TYPE_FN.name
mut fn_name := f.name mut fn_name := f.name
if f.is_method { if f.is_method {
receiver_type = receiver_type.replace('*', '') receiver_type = receiver_type.replace('*', '')
@ -454,7 +454,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
p.genln('$arg_struct_name * $tmp_struct = malloc(sizeof($arg_struct_name));') p.genln('$arg_struct_name * $tmp_struct = malloc(sizeof($arg_struct_name));')
mut arg_struct := 'typedef struct $arg_struct_name { ' mut arg_struct := 'typedef struct $arg_struct_name { '
p.next() p.next()
p.check(LPAR) p.check(.lpar)
// str_args contains the args for the wrapper function: // str_args contains the args for the wrapper function:
// wrapper(arg_struct * arg) { fn("arg->a, arg->b"); } // wrapper(arg_struct * arg) { fn("arg->a, arg->b"); }
mut str_args := '' mut str_args := ''
@ -473,7 +473,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
p.expression() p.expression()
p.genln(';') p.genln(';')
if i < f.args.len - 1 { if i < f.args.len - 1 {
p.check(COMMA) p.check(.comma)
str_args += ',' str_args += ','
} }
} }
@ -486,7 +486,7 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
// Create thread object // Create thread object
tmp_nr := p.get_tmp_counter() tmp_nr := p.get_tmp_counter()
thread_name = '_thread$tmp_nr' thread_name = '_thread$tmp_nr'
if p.os != WINDOWS { if p.os != .windows {
p.genln('pthread_t $thread_name;') p.genln('pthread_t $thread_name;')
} }
tmp2 := p.get_tmp() tmp2 := p.get_tmp()
@ -495,17 +495,17 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
parg = ' $tmp_struct' parg = ' $tmp_struct'
} }
// Call the wrapper // Call the wrapper
if p.os == WINDOWS { if p.os == .windows {
p.genln(' CreateThread(0,0, $wrapper_name, $parg, 0,0);') p.genln(' CreateThread(0,0, $wrapper_name, $parg, 0,0);')
} }
else { else {
p.genln('int $tmp2 = pthread_create(& $thread_name, NULL, $wrapper_name, $parg);') p.genln('int $tmp2 = pthread_create(& $thread_name, NULL, $wrapper_name, $parg);')
} }
p.check(RPAR) p.check(.rpar)
} }
fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type string) { fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type string) {
if !f.is_public && !f.is_c && !p.pref.is_test && !f.is_interface && f.pkg != p.pkg { if !f.is_public && !f.is_c && !p.pref.is_test && !f.is_interface && f.pkg != p.mod {
p.error('function `$f.name` is private') p.error('function `$f.name` is private')
} }
p.calling_c = f.is_c p.calling_c = f.is_c
@ -533,9 +533,9 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
receiver := f.args.first() receiver := f.args.first()
if receiver.is_mut && !p.expr_var.is_mut { if receiver.is_mut && !p.expr_var.is_mut {
println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut') println('$method_call recv=$receiver.name recv_mut=$receiver.is_mut')
p.error('`$p.expr_var.name` is immutable') p.error('`$p.expr_var.name` is imkey_mut')
} }
// if receiver is mutable or a ref (&), generate & for the first arg // if receiver is key_mut or a ref (&), generate & for the first arg
if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) { if receiver.ref || (receiver.is_mut && !receiver_type.contains('*')) {
method_call += '& /* ? */' method_call += '& /* ? */'
} }
@ -566,8 +566,8 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
// for declaration // for declaration
// return an updated Fn object with args[] field set // return an updated Fn object with args[] field set
fn (p mut Parser) fn_args(f mut Fn) { fn (p mut Parser) fn_args(f mut Fn) {
p.check(LPAR) p.check(.lpar)
// TODO defer p.check(RPAR) // TODO defer p.check(.rpar)
if f.is_interface { if f.is_interface {
int_arg := Var { int_arg := Var {
typ: f.receiver_typ typ: f.receiver_typ
@ -575,9 +575,9 @@ fn (p mut Parser) fn_args(f mut Fn) {
f.args << int_arg f.args << int_arg
} }
// Just register fn arg types // Just register fn arg types
types_only := p.tok == MUL || (p.peek() == COMMA && p.table.known_type(p.lit)) || p.peek() == RPAR// (int, string) types_only := p.tok == .mul || (p.peek() == .comma && p.table.known_type(p.lit)) || p.peek() == .rpar// (int, string)
if types_only { if types_only {
for p.tok != RPAR { for p.tok != .rpar {
typ := p.get_type() typ := p.get_type()
v := Var { v := Var {
typ: typ typ: typ
@ -587,24 +587,24 @@ fn (p mut Parser) fn_args(f mut Fn) {
} }
// f.register_var(v) // f.register_var(v)
f.args << v f.args << v
if p.tok == COMMA { if p.tok == .comma {
p.next() p.next()
} }
} }
} }
// (a int, b,c string) syntax // (a int, b,c string) syntax
for p.tok != RPAR { for p.tok != .rpar {
mut names := [ mut names := [
p.check_name() p.check_name()
] ]
// a,b,c int syntax // a,b,c int syntax
for p.tok == COMMA { for p.tok == .comma {
p.check(COMMA) p.check(.comma)
p.fspace() p.fspace()
names << p.check_name() names << p.check_name()
} }
p.fspace() p.fspace()
is_mut := p.tok == MUT is_mut := p.tok == .key_mut
if is_mut { if is_mut {
p.next() p.next()
} }
@ -628,17 +628,17 @@ fn (p mut Parser) fn_args(f mut Fn) {
f.register_var(v) f.register_var(v)
f.args << v f.args << v
} }
if p.tok == COMMA { if p.tok == .comma {
p.next() p.next()
} }
if p.tok == DOTDOT { if p.tok == .dotdot {
f.args << Var { f.args << Var {
name: '..' name: '..'
} }
p.next() p.next()
} }
} }
p.check(RPAR) p.check(.rpar)
} }
fn (p mut Parser) fn_call_args(f *Fn) *Fn { fn (p mut Parser) fn_call_args(f *Fn) *Fn {
@ -646,16 +646,16 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
// println('fn_call_args() name=$f.name args.len=$f.args.len') // println('fn_call_args() name=$f.name args.len=$f.args.len')
// C func. # of args is not known // C func. # of args is not known
// if f.name.starts_with('c_') { // if f.name.starts_with('c_') {
p.check(LPAR) p.check(.lpar)
if f.is_c { if f.is_c {
for p.tok != RPAR { for p.tok != .rpar {
p.bool_expression() p.bool_expression()
if p.tok == COMMA { if p.tok == .comma {
p.gen(', ') p.gen(', ')
p.check(COMMA) p.check(.comma)
} }
} }
p.check(RPAR) p.check(.rpar)
return f return f
} }
// Receiver - first arg // Receiver - first arg
@ -673,22 +673,27 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
break break
} }
ph := p.cgen.add_placeholder() ph := p.cgen.add_placeholder()
// ) here means not enough args were supplied // `)` here means that not enough args were provided
if p.tok == RPAR { if p.tok == .rpar {
str_args := f.str_args(p.table)// TODO this is C args str_args := f.str_args(p.table)// TODO this is C args
p.error('not enough arguments in call to `$f.name ($str_args)`') p.error('not enough arguments in call to `$f.name ($str_args)`')
} }
// If `arg` is mutable, the caller needs to provide MUT: // If `arg` is key_mut, the caller needs to provide `mut`:
// `arr := [1,2,3]; reverse(mut arr);` // `arr := [1,2,3]; reverse(mut arr);`
if arg.is_mut { if arg.is_mut {
if p.tok != MUT { if p.tok != .key_mut {
p.error('`$arg.name` is a mutable argument, you need to provide `mut`: `$f.name(...mut a...)`') p.error('`$arg.name` is a key_mut argument, you need to provide `mut`: `$f.name(...mut a...)`')
} }
if p.peek() != NAME { if p.peek() != .name {
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`') p.error('`$arg.name` is a key_mut argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
} }
p.check(MUT) p.check(.key_mut)
} }
p.expected_type = arg.typ
//TT := p.table.find_type(arg.typ)
//if arg.typ.parent == 'int' {
//p.expected_type =
//}
typ := p.bool_expression() typ := p.bool_expression()
// Optimize `println`: replace it with `printf` to avoid extra allocations and // Optimize `println`: replace it with `printf` to avoid extra allocations and
// function calls. `println(777)` => `printf("%d\n", 777)` // function calls. `println(777)` => `printf("%d\n", 777)`
@ -748,7 +753,7 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
if ! (expected == 'void*' && got == 'int') && if ! (expected == 'void*' && got == 'int') &&
! (expected == 'byte*' && got.contains(']byte')) && ! (expected == 'byte*' && got.contains(']byte')) &&
! (expected == 'byte*' && got == 'string') { ! (expected == 'byte*' && got == 'string') {
p.cgen.set_placeholder(ph, '& /*11 EXP:"$expected" GOT:"$got" */') p.cgen.set_placeholder(ph, '& /*11 EXP:"$expected" .key_goT:"$got" */')
} }
} }
} }
@ -767,10 +772,10 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
if i < f.args.len - 1 { if i < f.args.len - 1 {
// Handle 0 args passed to varargs // Handle 0 args passed to varargs
is_vararg := i == f.args.len - 2 && f.args[i + 1].name == '..' is_vararg := i == f.args.len - 2 && f.args[i + 1].name == '..'
if p.tok != COMMA && !is_vararg { if p.tok != .comma && !is_vararg {
p.error('wrong number of arguments for $i,$arg.name fn `$f.name`: expected $f.args.len, but got less') p.error('wrong number of arguments for $i,$arg.name fn `$f.name`: expected $f.args.len, but got less')
} }
if p.tok == COMMA { if p.tok == .comma {
p.fgen(', ') p.fgen(', ')
} }
if !is_vararg { if !is_vararg {
@ -783,20 +788,19 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
if f.args.len > 0 { if f.args.len > 0 {
last_arg := f.args.last() last_arg := f.args.last()
if last_arg.name == '..' { if last_arg.name == '..' {
println('GOT VAR ARGS AFTER') for p.tok != .rpar {
for p.tok != RPAR { if p.tok == .comma {
if p.tok == COMMA {
p.gen(',') p.gen(',')
p.check(COMMA) p.check(.comma)
} }
p.bool_expression() p.bool_expression()
} }
} }
} }
if p.tok == COMMA { if p.tok == .comma {
p.error('wrong number of arguments for fn `$f.name`: expected $f.args.len, but got more') p.error('wrong number of arguments for fn `$f.name`: expected $f.args.len, but got more')
} }
p.check(RPAR) p.check(.rpar)
// p.gen(')') // p.gen(')')
} }

View File

@ -28,7 +28,7 @@ fn (p mut Parser) gen_json_for_type(typ Type) {
// println('gen_json_for_type( $typ.name )') // println('gen_json_for_type( $typ.name )')
// Register decoder fn // Register decoder fn
mut dec_fn := Fn { mut dec_fn := Fn {
pkg: p.pkg pkg: p.mod
typ: 'Option_$typ.name' typ: 'Option_$typ.name'
name: js_dec_name(t) name: js_dec_name(t)
} }
@ -45,7 +45,7 @@ fn (p mut Parser) gen_json_for_type(typ Type) {
p.table.register_fn(dec_fn) p.table.register_fn(dec_fn)
// Register encoder fn // Register encoder fn
mut enc_fn := Fn { mut enc_fn := Fn {
pkg: p.pkg pkg: p.mod
typ: 'cJSON*' typ: 'cJSON*'
name: js_enc_name(t) name: js_enc_name(t)
} }

View File

@ -32,35 +32,31 @@ const (
TmpPath = vtmp_path() TmpPath = vtmp_path()
) )
enum Os { enum OS {
MAC mac
LINUX linux
WINDOWS windows
} }
enum Pass { enum Pass {
// A very short pass that only looks at imports in the begginning of each file // A very short pass that only looks at imports in the begginning of each file
RUN_IMPORTS imports
// First pass, only parses and saves declarations (fn signatures, consts, types). // First pass, only parses and saves declarations (fn signatures, consts, types).
// Skips function bodies. // Skips function bodies.
// We need this because in V things can be used before they are declared. // We need this because in V things can be used before they are declared.
RUN_DECLS decl
// Second pass, parses function bodies and generates C or machine code. // Second pass, parses function bodies and generates C or machine code.
RUN_MAIN
}
/*
// TODO rename to:
enum Pass {
imports
decls
main main
} }
*/
fn mykek(o OS) {
}
struct V { struct V {
mut: mut:
os Os // the OS to build for os OS // the OS to build for
out_name_c string // name of the temporary C file out_name_c string // name of the temporary C file
files []string // all V files that need to be parsed and compiled files []string // all V files that need to be parsed and compiled
dir string // directory (or file) being compiled (TODO rename to path?) dir string // directory (or file) being compiled (TODO rename to path?)
@ -125,7 +121,7 @@ fn main() {
} }
*/ */
// Just fmt and exit // Just fmt and exit
if args.contains('fmt') { if 'fmt' in args {
file := args.last() file := args.last()
if !os.file_exists(file) { if !os.file_exists(file) {
println('"$file" does not exist') println('"$file" does not exist')
@ -138,7 +134,7 @@ fn main() {
println('vfmt is temporarily disabled') println('vfmt is temporarily disabled')
return return
} }
// V with no args? REPL // No args? REPL
if args.len < 2 || (args.len == 2 && args[1] == '-') { if args.len < 2 || (args.len == 2 && args[1] == '-') {
run_repl() run_repl()
return return
@ -149,7 +145,7 @@ fn main() {
println(args) println(args)
} }
// Generate the docs and exit // Generate the docs and exit
if args.contains('doc') { if 'doc' in args {
// v.gen_doc_html_for_module(args.last()) // v.gen_doc_html_for_module(args.last())
exit(0) exit(0)
} }
@ -167,11 +163,11 @@ fn (v mut V) compile() {
} }
// First pass (declarations) // First pass (declarations)
for file in v.files { for file in v.files {
mut p := v.new_parser(file, RUN_DECLS) mut p := v.new_parser(file, Pass.decl)
p.parse() p.parse()
} }
// Main pass // Main pass
cgen.run = RUN_MAIN cgen.run = Pass.main
if v.pref.is_play { if v.pref.is_play {
cgen.genln('#define VPLAY (1) ') cgen.genln('#define VPLAY (1) ')
} }
@ -233,13 +229,13 @@ typedef map map_string;
#define false 0 #define false 0
#endif #endif
//============================== HELPER C MACROS =============================*/ //============================== HELPER C.MACROS =============================*/
#define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);} #define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);}
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push_many(arr, tmp.data, tmp.len);} #define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push_many(arr, tmp.data, tmp.len);}
#define _IN(typ, val, arr) array_##typ##_contains(arr, val) #define _IN(typ, val, arr) array_##typ##_contains(arr, val)
#define ALLOC_INIT(type, ...) (type *)memdup((type[]){ __VA_ARGS__ }, sizeof(type)) #define ALLOC_INIT(type, ...) (type *)memdup((type[]){ __VA_ARGS__ }, sizeof(type))
#define UTF8_CHAR_LEN( byte ) (( 0xE5000000 >> (( byte >> 3 ) & 0x1e )) & 3 ) + 1 #define UTF8_.chartoken_.leN( byte ) (( 0xE5000000 >> (( byte >> 3 ) & 0x1e )) & 3 ) + 1
//================================== GLOBALS =================================*/ //================================== GLOBALS =================================*/
//int V_ZERO = 0; //int V_ZERO = 0;
@ -249,7 +245,7 @@ void reload_so();
void init_consts();') void init_consts();')
imports_json := v.table.imports.contains('json') imports_json := v.table.imports.contains('json')
// TODO remove global UI hack // TODO remove global UI hack
if v.os == MAC && ((v.pref.build_mode == .embed_vlib && v.table.imports.contains('ui')) || if v.os == .mac && ((v.pref.build_mode == .embed_vlib && v.table.imports.contains('ui')) ||
(v.pref.build_mode == .build && v.dir.contains('/ui'))) { (v.pref.build_mode == .build && v.dir.contains('/ui'))) {
cgen.genln('id defaultFont = 0; // main.v') cgen.genln('id defaultFont = 0; // main.v')
} }
@ -284,7 +280,7 @@ void init_consts();')
cgen.genln('this line will be replaced with definitions') cgen.genln('this line will be replaced with definitions')
defs_pos := cgen.lines.len - 1 defs_pos := cgen.lines.len - 1
for file in v.files { for file in v.files {
mut p := v.new_parser(file, RUN_MAIN) mut p := v.new_parser(file, Pass.main)
p.parse() p.parse()
// p.g.gen_x64() // p.g.gen_x64()
// Format all files (don't format automatically generated vlib headers) // Format all files (don't format automatically generated vlib headers)
@ -294,7 +290,7 @@ void init_consts();')
} }
v.log('Done parsing.') v.log('Done parsing.')
// Write everything // Write everything
mut d := strings.new_builder(10000)// Just to avoid some unnecessary allocations mut d := strings.new_builder(10000)// Avoid unnecessary allocations
d.writeln(cgen.includes.join_lines()) d.writeln(cgen.includes.join_lines())
d.writeln(cgen.typedefs.join_lines()) d.writeln(cgen.typedefs.join_lines())
d.writeln(cgen.types.join_lines()) d.writeln(cgen.types.join_lines())
@ -524,7 +520,7 @@ fn (c &V) cc_windows_cross() {
fn (v mut V) cc() { fn (v mut V) cc() {
// Cross compiling for Windows // Cross compiling for Windows
if v.os == WINDOWS { if v.os == .windows {
$if !windows { $if !windows {
v.cc_windows_cross() v.cc_windows_cross()
return return
@ -580,7 +576,7 @@ mut args := ''
} }
// Cross compiling linux // Cross compiling linux
sysroot := '/Users/alex/tmp/lld/linuxroot/' sysroot := '/Users/alex/tmp/lld/linuxroot/'
if v.os == LINUX && !linux_host { if v.os == .linux && !linux_host {
// Build file.o // Build file.o
a << '-c --sysroot=$sysroot -target x86_64-linux-gnu' a << '-c --sysroot=$sysroot -target x86_64-linux-gnu'
// Right now `out_name` can be `file`, not `file.o` // Right now `out_name` can be `file`, not `file.o`
@ -597,17 +593,17 @@ mut args := ''
a << '"$TmpPath/$v.out_name_c"' a << '"$TmpPath/$v.out_name_c"'
// } // }
// Min macos version is mandatory I think? // Min macos version is mandatory I think?
if v.os == MAC { if v.os == .mac {
a << '-mmacosx-version-min=10.7' a << '-mmacosx-version-min=10.7'
} }
a << flags a << flags
a << libs a << libs
// macOS code can include objective C TODO remove once objective C is replaced with C // macOS code can include objective C TODO remove once objective C is replaced with C
if v.os == MAC { if v.os == .mac {
a << '-x objective-c' a << '-x objective-c'
} }
// Without these libs compilation will fail on Linux // Without these libs compilation will fail on Linux
if v.os == LINUX && v.pref.build_mode != .build { if v.os == .linux && v.pref.build_mode != .build {
a << '-lm -ldl -lpthread' a << '-lm -ldl -lpthread'
} }
// Find clang executable // Find clang executable
@ -634,7 +630,7 @@ mut args := ''
panic('clang error') panic('clang error')
} }
// Link it if we are cross compiling and need an executable // Link it if we are cross compiling and need an executable
if v.os == LINUX && !linux_host && v.pref.build_mode != .build { if v.os == .linux && !linux_host && v.pref.build_mode != .build {
v.out_name = v.out_name.replace('.o', '') v.out_name = v.out_name.replace('.o', '')
obj_file := v.out_name + '.o' obj_file := v.out_name + '.o'
println('linux obj_file=$obj_file out_name=$v.out_name') println('linux obj_file=$obj_file out_name=$v.out_name')
@ -680,20 +676,20 @@ fn (v &V) v_files_from_dir(dir string) []string {
if file.ends_with('_test.v') { if file.ends_with('_test.v') {
continue continue
} }
if file.ends_with('_win.v') && v.os != WINDOWS { if file.ends_with('_win.v') && v.os != .windows {
continue continue
} }
if file.ends_with('_lin.v') && v.os != LINUX { if file.ends_with('_lin.v') && v.os != .linux {
continue continue
} }
if file.ends_with('_mac.v') && v.os != MAC { if file.ends_with('_mac.v') && v.os != .mac {
lin_file := file.replace('_mac.v', '_lin.v') lin_file := file.replace('_mac.v', '_lin.v')
// println('lin_file="$lin_file"') // println('lin_file="$lin_file"')
// If there are both _mav.v and _lin.v, don't use _mav.v // If there are both _mav.v and _lin.v, don't use _mav.v
if os.file_exists('$dir/$lin_file') { if os.file_exists('$dir/$lin_file') {
continue continue
} }
else if v.os == WINDOWS { else if v.os == .windows {
continue continue
} }
else { else {
@ -719,7 +715,7 @@ fn (v mut V) add_user_v_files() {
if is_test_with_imports { if is_test_with_imports {
user_files << dir user_files << dir
pos := dir.last_index('/') pos := dir.last_index('/')
dir = dir.left(pos) + '/'// TODO WHY IS THIS NEEDED? dir = dir.left(pos) + '/'// TODO WHY IS THIS .neEDED?
} }
if dir.ends_with('.v') { if dir.ends_with('.v') {
// Just compile one file and get parent dir // Just compile one file and get parent dir
@ -743,7 +739,7 @@ fn (v mut V) add_user_v_files() {
} }
// Parse user imports // Parse user imports
for file in user_files { for file in user_files {
mut p := v.new_parser(file, RUN_IMPORTS) mut p := v.new_parser(file, Pass.imports)
p.parse() p.parse()
} }
// Parse lib imports // Parse lib imports
@ -753,7 +749,7 @@ fn (v mut V) add_user_v_files() {
vfiles := v.v_files_from_dir('$TmpPath/vlib/$pkg') vfiles := v.v_files_from_dir('$TmpPath/vlib/$pkg')
// Add all imports referenced by these libs // Add all imports referenced by these libs
for file in vfiles { for file in vfiles {
mut p := v.new_parser(file, RUN_IMPORTS) mut p := v.new_parser(file, Pass.imports)
p.parse() p.parse()
} }
} }
@ -771,7 +767,7 @@ fn (v mut V) add_user_v_files() {
vfiles := v.v_files_from_dir(import_path) vfiles := v.v_files_from_dir(import_path)
// Add all imports referenced by these libs // Add all imports referenced by these libs
for file in vfiles { for file in vfiles {
mut p := v.new_parser(file, RUN_IMPORTS) mut p := v.new_parser(file, Pass.imports)
p.parse() p.parse()
} }
} }
@ -890,24 +886,24 @@ fn new_v(args[]string) *V {
base := os.getwd().all_after('/') base := os.getwd().all_after('/')
out_name = base.trim_space() out_name = base.trim_space()
} }
mut _os := MAC mut _os := OS.mac
// No OS specifed? Use current system // No OS specifed? Use current system
if target_os == '' { if target_os == '' {
$if linux { $if linux {
_os = LINUX _os = .linux
} }
$if mac { $if mac {
_os = MAC _os = .mac
} }
$if windows { $if windows {
_os = WINDOWS _os = .windows
} }
} }
else { else {
switch target_os { switch target_os {
case 'linux': _os = LINUX case 'linux': _os = .linux
case 'windows': _os = WINDOWS case 'windows': _os = .windows
case 'mac': _os = MAC case 'mac': _os = .mac
} }
} }
builtins := [ builtins := [
@ -960,7 +956,7 @@ fn new_v(args[]string) *V {
mut f := '$lang_dir/vlib/builtin/$builtin' mut f := '$lang_dir/vlib/builtin/$builtin'
// In default mode we use precompiled vlib.o, point to .vh files with signatures // In default mode we use precompiled vlib.o, point to .vh files with signatures
if build_mode == .default_mode || build_mode == .build { if build_mode == .default_mode || build_mode == .build {
f = '$TmpPath/vlib/builtin/${builtin}h' //f = '$TmpPath/vlib/builtin/${builtin}h'
} }
files << f files << f
} }

File diff suppressed because it is too large Load Diff

View File

@ -148,7 +148,7 @@ fn (s mut Scanner) skip_whitespace() {
s.pos++ s.pos++
} }
// if s.pos == s.text.len { // if s.pos == s.text.len {
// return scan_res(EOF, '') // return scan_res(.eof, '')
// } // }
} }
@ -175,14 +175,14 @@ fn (s mut Scanner) scan() ScanRes {
} }
s.started = true s.started = true
if s.pos >= s.text.len { if s.pos >= s.text.len {
return scan_res(EOF, '') return scan_res(.eof, '')
} }
// skip whitespace // skip whitespace
if !s.inside_string { if !s.inside_string {
s.skip_whitespace() s.skip_whitespace()
} }
if s.is_fmt && s.text[s.pos] == `\n` { if s.is_fmt && s.text[s.pos] == `\n` {
return scan_res(NL, '') return scan_res(.nl, '')
} }
// End of $var, start next string // End of $var, start next string
if !s.is_fmt && s.dollar_end { if !s.is_fmt && s.dollar_end {
@ -190,16 +190,16 @@ fn (s mut Scanner) scan() ScanRes {
if s.text[s.pos] == SINGLE_QUOTE { if s.text[s.pos] == SINGLE_QUOTE {
// fmt.Println("ENDDD") // fmt.Println("ENDDD")
s.dollar_end = false s.dollar_end = false
return scan_res(STRING, '') return scan_res(.strtoken, '')
} }
s.dollar_end = false s.dollar_end = false
return scan_res(STRING, s.ident_string()) return scan_res(.strtoken, s.ident_string())
} }
s.skip_whitespace() s.skip_whitespace()
// end of file // end of file
if s.pos >= s.text.len { if s.pos >= s.text.len {
// println('scan(): returning EOF (pos >= len)') // println('scan(): returning .eof (pos >= len)')
return scan_res(EOF, '') return scan_res(.eof, '')
} }
// handle each char // handle each char
c := s.text[s.pos] c := s.text[s.pos]
@ -211,7 +211,7 @@ fn (s mut Scanner) scan() ScanRes {
if is_name_char(c) { if is_name_char(c) {
name := s.ident_name() name := s.ident_name()
// tmp hack to detect . in ${} // tmp hack to detect . in ${}
// Check if not EOF to prevent panic // Check if not .eof to prevent panic
next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` }
// println('!!! got name=$name next_char=$next_char') // println('!!! got name=$name next_char=$next_char')
if is_key(name) { if is_key(name) {
@ -232,7 +232,7 @@ fn (s mut Scanner) scan() ScanRes {
} }
} }
if s.dollar_start && next_char != `.` { if s.dollar_start && next_char != `.` {
// println('INSIDE STRING .dollar var=$name') // println('INSIDE .strtoken .dollar var=$name')
s.dollar_end = true s.dollar_end = true
s.dollar_start = false s.dollar_start = false
} }
@ -241,128 +241,128 @@ fn (s mut Scanner) scan() ScanRes {
//If a single letter name at the start of the file, increment //If a single letter name at the start of the file, increment
//Otherwise the scanner would be stuck at s.pos = 0 //Otherwise the scanner would be stuck at s.pos = 0
} }
return scan_res(NAME, name) return scan_res(.name, name)
} }
// number, `.123` // number, `.123`
else if c.is_digit() || c == `.` && nextc.is_digit() { else if c.is_digit() || c == `.` && nextc.is_digit() {
num := s.ident_number() num := s.ident_number()
return scan_res(INT, num) return scan_res(.integer, num)
} }
// all other tokens // all other tokens
switch c { switch c {
case `+`: case `+`:
if nextc == `+` { if nextc == `+` {
s.pos++ s.pos++
return scan_res(INC, '') return scan_res(.inc, '')
} }
else if nextc == `=` { else if nextc == `=` {
s.pos++ s.pos++
return scan_res(PLUS_ASSIGN, '') return scan_res(.plus_assign, '')
} }
return scan_res(PLUS, '') return scan_res(.plus, '')
case `-`: case `-`:
if nextc == `-` { if nextc == `-` {
s.pos++ s.pos++
return scan_res(DEC, '') return scan_res(.dec, '')
} }
else if nextc == `=` { else if nextc == `=` {
s.pos++ s.pos++
return scan_res(MINUS_ASSIGN, '') return scan_res(.minus_assign, '')
} }
return scan_res(MINUS, '') return scan_res(.minus, '')
case `*`: case `*`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(MULT_ASSIGN, '') return scan_res(.mult_assign, '')
} }
return scan_res(MUL, '') return scan_res(.mul, '')
case `^`: case `^`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(XOR_ASSIGN, '') return scan_res(.xor_assign, '')
} }
return scan_res(XOR, '') return scan_res(.xor, '')
case `%`: case `%`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(MOD_ASSIGN, '') return scan_res(.mod_assign, '')
} }
return scan_res(MOD, '') return scan_res(.mod, '')
case `?`: case `?`:
return scan_res(QUESTION, '') return scan_res(.question, '')
case SINGLE_QUOTE: case SINGLE_QUOTE:
return scan_res(STRING, s.ident_string()) return scan_res(.strtoken, s.ident_string())
// TODO allow double quotes // TODO allow double quotes
// case QUOTE: // case QUOTE:
// return scan_res(STRING, s.ident_string()) // return scan_res(.strtoken, s.ident_string())
case `\``: case `\``:
return scan_res(CHAR, s.ident_char()) return scan_res(.chartoken, s.ident_char())
case `(`: case `(`:
return scan_res(LPAR, '') return scan_res(.lpar, '')
case `)`: case `)`:
return scan_res(RPAR, '') return scan_res(.rpar, '')
case `[`: case `[`:
return scan_res(LSBR, '') return scan_res(.lsbr, '')
case `]`: case `]`:
return scan_res(RSBR, '') return scan_res(.rsbr, '')
case `{`: case `{`:
// Skip { in ${ in strings // Skip { in ${ in strings
if s.inside_string { if s.inside_string {
return s.scan() return s.scan()
} }
return scan_res(LCBR, '') return scan_res(.lcbr, '')
case `$`: case `$`:
return scan_res(DOLLAR, '') return scan_res(.dollar, '')
case `}`: case `}`:
// s = `hello $name kek` // s = `hello $name kek`
// s = `hello ${name} kek` // s = `hello ${name} kek`
if s.inside_string { if s.inside_string {
s.pos++ s.pos++
// TODO UNNEEDED? // TODO UN.neEDED?
if s.text[s.pos] == SINGLE_QUOTE { if s.text[s.pos] == SINGLE_QUOTE {
s.inside_string = false s.inside_string = false
return scan_res(STRING, '') return scan_res(.strtoken, '')
} }
return scan_res(STRING, s.ident_string()) return scan_res(.strtoken, s.ident_string())
} }
else { else {
return scan_res(RCBR, '') return scan_res(.rcbr, '')
} }
case `&`: case `&`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(AND_ASSIGN, '') return scan_res(.and_assign, '')
} }
if nextc == `&` { if nextc == `&` {
s.pos++ s.pos++
return scan_res(AND, '') return scan_res(.and, '')
} }
return scan_res(AMP, '') return scan_res(.amp, '')
case `|`: case `|`:
if nextc == `|` { if nextc == `|` {
s.pos++ s.pos++
return scan_res(OR, '') return scan_res(.ortok, '')
} }
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(OR_ASSIGN, '') return scan_res(.or_assign, '')
} }
return scan_res(PIPE, '') return scan_res(.pipe, '')
case `,`: case `,`:
return scan_res(COMMA, '') return scan_res(.comma, '')
case `\r`: case `\r`:
if nextc == `\n` { if nextc == `\n` {
s.pos++ s.pos++
return scan_res(NL, '') return scan_res(.nl, '')
} }
case `\n`: case `\n`:
return scan_res(NL, '') return scan_res(.nl, '')
case `.`: case `.`:
if nextc == `.` { if nextc == `.` {
s.pos++ s.pos++
return scan_res(DOTDOT, '') return scan_res(.dotdot, '')
} }
return scan_res(DOT, '') return scan_res(.dot, '')
case `#`: case `#`:
start := s.pos + 1 start := s.pos + 1
for s.pos < s.text.len && s.text[s.pos] != `\n` { for s.pos < s.text.len && s.text[s.pos] != `\n` {
@ -374,74 +374,74 @@ fn (s mut Scanner) scan() ScanRes {
// fmt needs NL after # // fmt needs NL after #
s.pos-- s.pos--
} }
return scan_res(HASH, hash.trim_space()) return scan_res(.hash, hash.trim_space())
case `>`: case `>`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(GE, '') return scan_res(.ge, '')
} }
else if nextc == `>` { else if nextc == `>` {
if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` {
s.pos += 2 s.pos += 2
return scan_res(RIGHT_SHIFT_ASSIGN, '') return scan_res(.righ_shift_assign, '')
} }
s.pos++ s.pos++
return scan_res(RIGHT_SHIFT, '') return scan_res(.righ_shift, '')
} }
else { else {
return scan_res(GT, '') return scan_res(.gt, '')
} }
case `<`: case `<`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(LE, '') return scan_res(.le, '')
} }
else if nextc == `<` { else if nextc == `<` {
if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` {
s.pos += 2 s.pos += 2
return scan_res(LEFT_SHIFT_ASSIGN, '') return scan_res(.left_shift_assign, '')
} }
s.pos++ s.pos++
return scan_res(LEFT_SHIFT, '') return scan_res(.left_shift, '')
} }
else { else {
return scan_res(LT, '') return scan_res(.lt, '')
} }
case `=`: case `=`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(EQ, '') return scan_res(.eq, '')
} }
else { else {
return scan_res(ASSIGN, '') return scan_res(.assign, '')
} }
case `:`: case `:`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(DECL_ASSIGN, '') return scan_res(.decl_assign, '')
} }
else { else {
return scan_res(COLON, '') return scan_res(.colon, '')
} }
case `;`: case `;`:
return scan_res(SEMICOLON, '') return scan_res(.semicolon, '')
case `!`: case `!`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(NE, '') return scan_res(.ne, '')
} }
else { else {
return scan_res(NOT, '') return scan_res(.not, '')
} }
case `~`: case `~`:
return scan_res(BIT_NOT, '') return scan_res(.bit_not, '')
case `/`: case `/`:
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(DIV_ASSIGN, '') return scan_res(.div_assign, '')
} }
if nextc == `/` { if nextc == `/` {
// debug("!!!!!!GOT LINE COM") // debug("!!!!!!.key_goT LI.ne COM")
start := s.pos + 1 start := s.pos + 1
for s.pos < s.text.len && s.text[s.pos] != `\n`{ for s.pos < s.text.len && s.text[s.pos] != `\n`{
s.pos++ s.pos++
@ -458,7 +458,7 @@ fn (s mut Scanner) scan() ScanRes {
// Skip comment // Skip comment
return s.scan() return s.scan()
} }
return scan_res(LINE_COM, s.line_comment) return scan_res(.line_com, s.line_comment)
} }
// Multiline comments // Multiline comments
if nextc == `*` { if nextc == `*` {
@ -488,16 +488,16 @@ fn (s mut Scanner) scan() ScanRes {
comm := s.text.substr(start, end) comm := s.text.substr(start, end)
s.fgenln(comm) s.fgenln(comm)
if s.is_fmt { if s.is_fmt {
return scan_res(MLINE_COM, comm) return scan_res(.mline_com, comm)
} }
// Skip if not in fmt mode // Skip if not in fmt mode
return s.scan() return s.scan()
} }
return scan_res(DIV, '') return scan_res(.div, '')
} }
$if windows { $if windows {
if c == `\0` { if c == `\0` {
return scan_res(EOF, '') return scan_res(.eof, '')
} }
} }
println('(char code=$c) pos=$s.pos len=$s.text.len') println('(char code=$c) pos=$s.pos len=$s.text.len')
@ -506,7 +506,7 @@ fn (s mut Scanner) scan() ScanRes {
msg += ', use \' to denote strings' msg += ', use \' to denote strings'
} }
s.error(msg) s.error(msg)
return scan_res(EOF, '') return scan_res(.eof, '')
} }
fn (s &Scanner) error(msg string) { fn (s &Scanner) error(msg string) {
@ -637,7 +637,7 @@ fn (s mut Scanner) ident_char() string {
fn (p mut Parser) peek() Token { fn (p mut Parser) peek() Token {
for { for {
tok := p.scanner.peek() tok := p.scanner.peek()
if tok != NL { if tok != .nl {
return tok return tok
} }
} }
@ -681,7 +681,7 @@ fn (s mut Scanner) debug_tokens() {
println('') println('')
} }
// allToks += "\n" // allToks += "\n"
if tok == EOF { if tok == .eof {
println('============ END OF DEBUG TOKENS ==================') println('============ END OF DEBUG TOKENS ==================')
// fmt.Println("========"+s.file+"========\n", allToks) // fmt.Println("========"+s.file+"========\n", allToks)
break break

View File

@ -18,24 +18,25 @@ mut:
} }
enum AccessMod { enum AccessMod {
PRIVATE // private immutable private // private imkey_mut
PRIVET_MUT // private mutable private_mut // private key_mut
PUBLIC // public immmutable (readonly) public // public immkey_mut (readonly)
PUBLIC_MUT // public, but mutable only in this module public_mut // public, but key_mut only in this module
PUBLIC_MUT_MUT // public and mutable both inside and outside (not recommended to use, that's why it's so verbose) public_mut_mut // public and key_mut both inside and outside (not recommended to use, that's why it's so verbose)
} }
struct Type { struct Type {
mut: mut:
pkg string mod string
name string name string
fields []Var fields []Var
methods []Fn methods []Fn
parent string parent string
func Fn // For cat == FN (type kek fn()) func Fn // For cat == FN (type kek fn())
is_c bool // C.FILE is_c bool // C.FI.le
is_interface bool is_interface bool
is_enum bool is_enum bool
enum_vals []string
// This field is used for types that are not defined yet but are known to exist. // This field is used for types that are not defined yet but are known to exist.
// It allows having things like `fn (f Foo) bar()` before `Foo` is defined. // It allows having things like `fn (f Foo) bar()` before `Foo` is defined.
// This information is needed in the first pass. // This information is needed in the first pass.
@ -117,8 +118,7 @@ fn new_table(obfuscate bool) *Table {
t.register_type_with_parent('i32', 'int') t.register_type_with_parent('i32', 'int')
t.register_type_with_parent('u32', 'int') t.register_type_with_parent('u32', 'int')
t.register_type_with_parent('byte', 'int') t.register_type_with_parent('byte', 'int')
// t.register_type_with_parent('i64', 'int') t.register_type_with_parent('i64', 'int')
t.register_type('i64')
t.register_type_with_parent('u64', 'int') t.register_type_with_parent('u64', 'int')
t.register_type('byteptr') t.register_type('byteptr')
t.register_type('intptr') t.register_type('intptr')
@ -159,13 +159,13 @@ fn (table &Table) known_pkg(pkg string) bool {
return pkg in table.packages return pkg in table.packages
} }
fn (t mut Table) register_const(name, typ, pkg string, is_imported bool) { fn (t mut Table) register_const(name, typ, mod string, is_imported bool) {
t.consts << Var { t.consts << Var {
name: name name: name
typ: typ typ: typ
is_const: true is_const: true
is_import_const: is_imported is_import_const: is_imported
pkg: pkg mod: mod
} }
} }
@ -176,7 +176,7 @@ fn (p mut Parser) register_global(name, typ string) {
typ: typ typ: typ
is_const: true is_const: true
is_global: true is_global: true
pkg: p.pkg mod: p.mod
} }
} }
@ -237,7 +237,7 @@ fn (p mut Parser) register_type_with_parent(strtyp, parent string) {
typ := Type { typ := Type {
name: strtyp name: strtyp
parent: parent parent: parent
pkg: p.pkg mod: p.mod
} }
p.table.register_type2(typ) p.table.register_type2(typ)
} }
@ -297,6 +297,10 @@ fn (t &Type) has_field(name string) bool {
return (field.name != '') return (field.name != '')
} }
fn (t &Type) has_enum_val(name string) bool {
return name in t.enum_vals
}
fn (t &Type) find_field(name string) Var { fn (t &Type) find_field(name string) Var {
for field in t.fields { for field in t.fields {
if field.name == name { if field.name == name {

View File

@ -5,214 +5,212 @@
module main module main
enum Token { enum Token {
EOF eof
NAME name
INT integer
STRING strtoken
CHAR chartoken
PLUS plus
MINUS minus
MUL mul
DIV div
MOD mod
XOR xor
PIPE pipe
INC inc
DEC dec
AND and
OR ortok
NOT not
BIT_NOT bit_not
QUESTION question
COMMA comma
SEMICOLON semicolon
COLON colon
AMP amp
HASH hash
DOLLAR dollar
LEFT_SHIFT left_shift
RIGHT_SHIFT righ_shift
// = := += -= // = := += -=
ASSIGN assign
DECL_ASSIGN decl_assign
PLUS_ASSIGN plus_assign
MINUS_ASSIGN minus_assign
DIV_ASSIGN div_assign
MULT_ASSIGN mult_assign
XOR_ASSIGN xor_assign
MOD_ASSIGN mod_assign
OR_ASSIGN or_assign
AND_ASSIGN and_assign
RIGHT_SHIFT_ASSIGN righ_shift_assign
LEFT_SHIFT_ASSIGN left_shift_assign
// {} () [] // {} () []
LCBR lcbr
RCBR rcbr
LPAR lpar
RPAR rpar
LSBR lsbr
RSBR rsbr
// == != <= < >= > // == != <= < >= >
EQ eq
NE ne
GT gt
LT lt
GE ge
LE le
// comments // comments
LINE_COM line_com
MLINE_COM mline_com
NL nl
DOT dot
DOTDOT dotdot
// keywords // keywords
keyword_beg keyword_beg
PACKAGE key_module
// MODULE key_struct
STRUCT key_if
IF key_else
ELSE key_return
RETURN key_go
GO key_const
CONST key_import_const
IMPORT_CONST key_mut
MUT typ
TIP key_enum
ENUM key_for
FOR key_switch
SWITCH
MATCH MATCH
CASE key_case
FUNC func
TRUE key_true
FALSE key_false
CONTINUE key_continue
BREAK key_break
EMBED key_embed
IMPORT key_import
TYPEOF //typeof
DEFAULT key_default
ENDIF key_assert
ASSERT key_sizeof
SIZEOF key_in
IN key_atomic
ATOMIC key_interface
INTERFACE key_orelse
OR_ELSE key_global
GLOBAL key_union
UNION key_pub
PUB key_goto
GOTO key_static
STATIC
keyword_end keyword_end
} }
// build_keys genereates a map with keywords' string values: // build_keys genereates a map with keywords' string values:
// Keywords['return'] == .return // Keywords['return'] == .key_return
fn build_keys() map_int { fn build_keys() map_int {
mut res := map[string]int{} mut res := map[string]int{}
for t := int(keyword_beg) + 1; t < int(keyword_end); t++ { for t := int(Token.keyword_beg) + 1; t < int(Token.keyword_end); t++ {
key := TOKENSTR[t] key := TOKENSTR[t]
res[key] = int(t) res[key] = int(t)
} }
return res return res
} }
// TODO remove once we have `enum Token { name('name') if('if') ... }`
fn build_token_str() []string { fn build_token_str() []string {
mut s := [''; NrTokens] mut s := [''; NrTokens]
s[keyword_beg] = '' s[Token.keyword_beg] = ''
s[keyword_end] = '' s[Token.keyword_end] = ''
s[EOF] = 'EOF' s[Token.eof] = '.eof'
s[NAME] = 'NAME' s[Token.name] = '.name'
s[INT] = 'INT' s[Token.integer] = '.integer'
s[STRING] = 'STR' s[Token.strtoken] = 'STR'
s[CHAR] = 'CHAR' s[Token.chartoken] = '.chartoken'
s[PLUS] = '+' s[Token.plus] = '+'
s[MINUS] = '-' s[Token.minus] = '-'
s[MUL] = '*' s[Token.mul] = '*'
s[DIV] = '/' s[Token.div] = '/'
s[MOD] = '%' s[Token.mod] = '%'
s[XOR] = '^' s[Token.xor] = '^'
s[BIT_NOT] = '~' s[Token.bit_not] = '~'
s[PIPE] = '|' s[Token.pipe] = '|'
s[HASH] = '#' s[Token.hash] = '#'
s[AMP] = '&' s[Token.amp] = '&'
s[INC] = '++' s[Token.inc] = '++'
s[DEC] = '--' s[Token.dec] = '--'
s[AND] = '&&' s[Token.and] = '&&'
s[OR] = '||' s[Token.ortok] = '||'
s[NOT] = '!' s[Token.not] = '!'
s[DOT] = '.' s[Token.dot] = '.'
s[DOTDOT] = '..' s[Token.dotdot] = '..'
s[COMMA] = ',' s[Token.comma] = ','
s[SEMICOLON] = ';' s[Token.semicolon] = ';'
s[COLON] = ':' s[Token.colon] = ':'
s[ASSIGN] = '=' s[Token.assign] = '='
s[DECL_ASSIGN] = ':=' s[Token.decl_assign] = ':='
s[PLUS_ASSIGN] = '+=' s[Token.plus_assign] = '+='
s[MINUS_ASSIGN] = '-=' s[Token.minus_assign] = '-='
s[MULT_ASSIGN] = '*=' s[Token.mult_assign] = '*='
s[DIV_ASSIGN] = '/=' s[Token.div_assign] = '/='
s[XOR_ASSIGN] = '^=' s[Token.xor_assign] = '^='
s[MOD_ASSIGN] = '%=' s[Token.mod_assign] = '%='
s[OR_ASSIGN] = '|=' s[Token.or_assign] = '|='
s[AND_ASSIGN] = '&=' s[Token.and_assign] = '&='
s[RIGHT_SHIFT_ASSIGN] = '>>=' s[Token.righ_shift_assign] = '>>='
s[LEFT_SHIFT_ASSIGN] = '<<=' s[Token.left_shift_assign] = '<<='
s[LCBR] = '{' s[Token.lcbr] = '{'
s[RCBR] = '}' s[Token.rcbr] = '}'
s[LPAR] = '(' s[Token.lpar] = '('
s[RPAR] = ')' s[Token.rpar] = ')'
s[LSBR] = '[' s[Token.lsbr] = '['
s[RSBR] = ']' s[Token.rsbr] = ']'
s[EQ] = '==' s[Token.eq] = '=='
s[NE] = '!=' s[Token.ne] = '!='
s[GT] = '>' s[Token.gt] = '>'
s[LT] = '<' s[Token.lt] = '<'
s[GE] = '>=' s[Token.ge] = '>='
s[LE] = '<=' s[Token.le] = '<='
s[QUESTION] = '?' s[Token.question] = '?'
s[LEFT_SHIFT] = '<<' s[Token.left_shift] = '<<'
s[RIGHT_SHIFT] = '>>' s[Token.righ_shift] = '>>'
s[LINE_COM] = '//' s[Token.line_com] = '//'
s[NL] = 'NLL' s[Token.nl] = 'NLL'
s[DOLLAR] = '$' s[Token.dollar] = '$'
s[ASSERT] = 'assert' s[Token.key_assert] = 'assert'
s[STRUCT] = 'struct' s[Token.key_struct] = 'struct'
s[IF] = 'if' s[Token.key_if] = 'if'
s[ELSE] = 'else' s[Token.key_else] = 'else'
s[RETURN] = 'return' s[Token.key_return] = 'return'
s[PACKAGE] = 'module' s[Token.key_module] = 'module'
s[SIZEOF] = 'sizeof' s[Token.key_sizeof] = 'sizeof'
s[GO] = 'go' s[Token.key_go] = 'go'
s[GOTO] = 'goto' s[Token.key_goto] = 'goto'
s[CONST] = 'const' s[Token.key_const] = 'const'
s[MUT] = 'mut' s[Token.key_mut] = 'mut'
s[TIP] = 'type' s[Token.typ] = 'type'
s[FOR] = 'for' s[Token.key_for] = 'for'
s[SWITCH] = 'switch' s[Token.key_switch] = 'switch'
s[MATCH] = 'match' //Tokens[MATCH] = 'match'
s[CASE] = 'case' s[Token.key_case] = 'case'
s[FUNC] = 'fn' s[Token.func] = 'fn'
s[TRUE] = 'true' s[Token.key_true] = 'true'
s[FALSE] = 'false' s[Token.key_false] = 'false'
s[CONTINUE] = 'continue' s[Token.key_continue] = 'continue'
s[BREAK] = 'break' s[Token.key_break] = 'break'
s[IMPORT] = 'import' s[Token.key_import] = 'import'
s[EMBED] = 'embed' s[Token.key_embed] = 'embed'
s[TYPEOF] = 'typeof' //Tokens[TYP.eof] = 'typeof'
s[DEFAULT] = 'default' s[Token.key_default] = 'default'
s[ENDIF] = 'endif' s[Token.key_enum] = 'enum'
s[ENUM] = 'enum' s[Token.key_interface] = 'interface'
s[INTERFACE] = 'interface' s[Token.key_pub] = 'pub'
s[PUB] = 'pub' s[Token.key_import_const] = 'import_const'
s[IMPORT_CONST] = 'import_const' s[Token.key_in] = 'in'
s[IN] = 'in' s[Token.key_atomic] = 'atomic'
s[ATOMIC] = 'atomic' s[Token.key_orelse] = 'or'
s[OR_ELSE] = 'or' s[Token.key_global] = '__global'
s[GLOBAL] = '__global' s[Token.key_union] = 'union'
s[UNION] = 'union' s[Token.key_static] = 'static'
s[STATIC] = 'static'
return s return s
} }
@ -236,17 +234,19 @@ fn (t Token) str() string {
} }
fn (t Token) is_decl() bool { fn (t Token) is_decl() bool {
// TODO return t in [FUNC ,TIP, CONST, IMPORT_CONST ,AT ,EOF] // TODO return t in [.func ,.typ, .key_const, .key_import_.key_const ,AT ,.eof]
return t == ENUM || t == INTERFACE || t == FUNC || t == STRUCT || t == TIP || return t == .key_enum || t == .key_interface || t == .func ||
t == CONST || t == IMPORT_CONST || t == PUB || t == EOF t == .key_struct || t == .typ ||
t == .key_const || t == .key_import_const || t == .key_pub || t == .eof
} }
const ( const (
AssignTokens = [ AssignTokens = [
ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN, Token.assign, Token.plus_assign, Token.minus_assign,
MULT_ASSIGN, DIV_ASSIGN, XOR_ASSIGN, MOD_ASSIGN, Token.mult_assign, Token.div_assign, Token.xor_assign,
OR_ASSIGN, AND_ASSIGN, RIGHT_SHIFT_ASSIGN, Token.mod_assign,
LEFT_SHIFT_ASSIGN Token.or_assign, Token.and_assign, Token.righ_shift_assign,
Token.left_shift_assign
] ]
) )