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) {
if g.nogen || g.run == RUN_DECLS {
if g.nogen || g.run == .decl {
return
}
if g.is_tmp {
@ -61,7 +61,7 @@ fn (g mut CGen) genln(s string) {
}
fn (g mut CGen) gen(s string) {
if g.nogen || g.run == RUN_DECLS {
if g.nogen || g.run == .decl {
return
}
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.
fn (p mut Parser) fn_decl() {
p.fgen('fn ')
is_pub := p.tok == PUB
is_pub := p.tok == .key_pub
is_live := p.attr == 'live' && !p.pref.is_so
if is_live && !p.pref.is_live {
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.next()
mut f := new_fn(p.pkg, is_pub)
mut f := new_fn(p.mod, is_pub)
// Method receiver
mut receiver_typ := ''
if p.tok == LPAR {
if p.tok == .lpar {
f.is_method = true
p.check(LPAR)
p.check(.lpar)
receiver_name := p.check_name()
is_mut := p.tok == MUT
is_amp := p.tok == AMP
is_mut := p.tok == .key_mut
is_amp := p.tok == .amp
if is_mut || is_amp {
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)')
}
// Don't allow modifying types from a different module
if !p.first_run() && !p.builtin_pkg && T.pkg != p.pkg {
println('T.pkg=$T.pkg')
println('pkg=$p.pkg')
if !p.first_run() && !p.builtin_pkg && T.mod != p.mod {
println('T.mod=$T.mod')
println('pkg=$p.mod')
p.error('cannot define new methods on non-local type `$receiver_typ`')
}
// (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 {
receiver_typ += '*'
}
p.check(RPAR)
p.check(.rpar)
p.fspace()
receiver := Var {
name: receiver_name
@ -170,7 +170,7 @@ fn (p mut Parser) fn_decl() {
f.args << 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()
p.next()
}
@ -178,14 +178,14 @@ fn (p mut Parser) fn_decl() {
f.name = p.check_name()
}
// 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
// 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.is_sig()
// println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg')
if is_c {
p.check(DOT)
p.check(.dot)
f.name = p.check_name()
f.is_c = true
}
@ -198,7 +198,7 @@ fn (p mut Parser) fn_decl() {
}
}
// simple_name := f.name
// println('!SIMPLE=$simple_name')
// println('!SIMP.le=$simple_name')
// user.register() => User_register()
has_receiver := receiver_typ.len > 0
if receiver_typ != '' {
@ -206,7 +206,7 @@ fn (p mut Parser) fn_decl() {
}
// full pkg function name
// 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)
}
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?
mut is_generic := false
if p.tok == LT {
if p.tok == .lt {
p.next()
gen_type := p.check_name()
if gen_type != 'T' {
p.error('only `T` is allowed as a generic type for now')
}
p.check(GT)
p.check(.gt)
is_generic = true
}
// Args (...)
p.fn_args(mut f)
// Returns an error?
if p.tok == NOT {
if p.tok == .not {
p.next()
f.returns_error = true
}
// Returns a type?
mut typ := 'void'
if p.tok == NAME || p.tok == MUL || p.tok == AMP || p.tok == LSBR ||
p.tok == QUESTION {
if p.tok == .name || p.tok == .mul || p.tok == .amp || p.tok == .lsbr ||
p.tok == .question {
p.fgen(' ')
// TODO In
// if p.tok in [ NAME, MUL, AMP, LSBR ] {
// if p.tok in [ .name, .mul, .amp, .lsbr ] {
typ = p.get_type()
}
// Translated C code can have empty functions (just definitions)
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 {
f.is_decl = true
// println('GOT fn header $f.name')
// println('.key_goT fn header $f.name')
}
// { required only in normal function declarations
if !is_c && !is_sig && !is_fn_header {
p.fgen(' ')
p.check(LCBR)
p.check(.lcbr)
}
// Register option ? type
if typ.starts_with('Option_') {
@ -262,7 +262,7 @@ fn (p mut Parser) fn_decl() {
// Register function
f.typ = typ
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
if f.name == 'main' && !has_receiver {
if str_args != '' || typ != 'void' {
@ -305,7 +305,7 @@ fn (p mut Parser) fn_decl() {
// println('fn decl !!!!!!! REG PH $receiver_typ')
ttyp := Type {
name: receiver_typ.replace('*', '')
pkg: p.pkg
mod: p.mod
is_placeholder: true
}
p.table.register_type2(ttyp)
@ -328,7 +328,7 @@ fn (p mut Parser) fn_decl() {
}
}
// 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')
p.cgen.so_fns << 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')
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')
return
}
@ -395,15 +395,15 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
p.error('$f.name must return "$typ"')
}
// {} closed correctly? scope_level should be 0
if p.pkg == 'main' {
if p.mod == 'main' {
// println(p.cur_fn.scope_level)
}
if p.cur_fn.scope_level > 2 {
// p.error('unclosed {')
}
// 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.pkg != 'main' {
// if p.builtin_pkg || p.mod == 'os' ||p.mod=='http'{
if p.mod != 'main' {
p.genln('}')
p.fgenln('\n')
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')
// p.print_tok()
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
if f.is_method {
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));')
mut arg_struct := 'typedef struct $arg_struct_name { '
p.next()
p.check(LPAR)
p.check(.lpar)
// str_args contains the args for the wrapper function:
// wrapper(arg_struct * arg) { fn("arg->a, arg->b"); }
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.genln(';')
if i < f.args.len - 1 {
p.check(COMMA)
p.check(.comma)
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
tmp_nr := p.get_tmp_counter()
thread_name = '_thread$tmp_nr'
if p.os != WINDOWS {
if p.os != .windows {
p.genln('pthread_t $thread_name;')
}
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'
}
// Call the wrapper
if p.os == WINDOWS {
if p.os == .windows {
p.genln(' CreateThread(0,0, $wrapper_name, $parg, 0,0);')
}
else {
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) {
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.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()
if receiver.is_mut && !p.expr_var.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('*')) {
method_call += '& /* ? */'
}
@ -566,8 +566,8 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
// for declaration
// return an updated Fn object with args[] field set
fn (p mut Parser) fn_args(f mut Fn) {
p.check(LPAR)
// TODO defer p.check(RPAR)
p.check(.lpar)
// TODO defer p.check(.rpar)
if f.is_interface {
int_arg := Var {
typ: f.receiver_typ
@ -575,9 +575,9 @@ fn (p mut Parser) fn_args(f mut Fn) {
f.args << int_arg
}
// 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 {
for p.tok != RPAR {
for p.tok != .rpar {
typ := p.get_type()
v := Var {
typ: typ
@ -587,24 +587,24 @@ fn (p mut Parser) fn_args(f mut Fn) {
}
// f.register_var(v)
f.args << v
if p.tok == COMMA {
if p.tok == .comma {
p.next()
}
}
}
// (a int, b,c string) syntax
for p.tok != RPAR {
for p.tok != .rpar {
mut names := [
p.check_name()
]
// a,b,c int syntax
for p.tok == COMMA {
p.check(COMMA)
for p.tok == .comma {
p.check(.comma)
p.fspace()
names << p.check_name()
}
p.fspace()
is_mut := p.tok == MUT
is_mut := p.tok == .key_mut
if is_mut {
p.next()
}
@ -628,17 +628,17 @@ fn (p mut Parser) fn_args(f mut Fn) {
f.register_var(v)
f.args << v
}
if p.tok == COMMA {
if p.tok == .comma {
p.next()
}
if p.tok == DOTDOT {
if p.tok == .dotdot {
f.args << Var {
name: '..'
}
p.next()
}
}
p.check(RPAR)
p.check(.rpar)
}
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')
// C func. # of args is not known
// if f.name.starts_with('c_') {
p.check(LPAR)
p.check(.lpar)
if f.is_c {
for p.tok != RPAR {
for p.tok != .rpar {
p.bool_expression()
if p.tok == COMMA {
if p.tok == .comma {
p.gen(', ')
p.check(COMMA)
p.check(.comma)
}
}
p.check(RPAR)
p.check(.rpar)
return f
}
// Receiver - first arg
@ -673,22 +673,27 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
break
}
ph := p.cgen.add_placeholder()
// ) here means not enough args were supplied
if p.tok == RPAR {
// `)` here means that not enough args were provided
if p.tok == .rpar {
str_args := f.str_args(p.table)// TODO this is C 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);`
if arg.is_mut {
if p.tok != MUT {
p.error('`$arg.name` is a mutable argument, you need to provide `mut`: `$f.name(...mut a...)`')
if p.tok != .key_mut {
p.error('`$arg.name` is a key_mut argument, you need to provide `mut`: `$f.name(...mut a...)`')
}
if p.peek() != NAME {
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`')
if p.peek() != .name {
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()
// Optimize `println`: replace it with `printf` to avoid extra allocations and
// 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') &&
! (expected == 'byte*' && got.contains(']byte')) &&
! (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 {
// Handle 0 args passed to varargs
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')
}
if p.tok == COMMA {
if p.tok == .comma {
p.fgen(', ')
}
if !is_vararg {
@ -783,20 +788,19 @@ fn (p mut Parser) fn_call_args(f *Fn) *Fn {
if f.args.len > 0 {
last_arg := f.args.last()
if last_arg.name == '..' {
println('GOT VAR ARGS AFTER')
for p.tok != RPAR {
if p.tok == COMMA {
for p.tok != .rpar {
if p.tok == .comma {
p.gen(',')
p.check(COMMA)
p.check(.comma)
}
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.check(RPAR)
p.check(.rpar)
// 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 )')
// Register decoder fn
mut dec_fn := Fn {
pkg: p.pkg
pkg: p.mod
typ: 'Option_$typ.name'
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)
// Register encoder fn
mut enc_fn := Fn {
pkg: p.pkg
pkg: p.mod
typ: 'cJSON*'
name: js_enc_name(t)
}

View File

@ -32,35 +32,31 @@ const (
TmpPath = vtmp_path()
)
enum Os {
MAC
LINUX
WINDOWS
enum OS {
mac
linux
windows
}
enum Pass {
// 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).
// Skips function bodies.
// 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.
RUN_MAIN
}
/*
// TODO rename to:
enum Pass {
imports
decls
main
}
*/
fn mykek(o OS) {
}
struct V {
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
files []string // all V files that need to be parsed and compiled
dir string // directory (or file) being compiled (TODO rename to path?)
@ -125,7 +121,7 @@ fn main() {
}
*/
// Just fmt and exit
if args.contains('fmt') {
if 'fmt' in args {
file := args.last()
if !os.file_exists(file) {
println('"$file" does not exist')
@ -138,7 +134,7 @@ fn main() {
println('vfmt is temporarily disabled')
return
}
// V with no args? REPL
// No args? REPL
if args.len < 2 || (args.len == 2 && args[1] == '-') {
run_repl()
return
@ -149,7 +145,7 @@ fn main() {
println(args)
}
// Generate the docs and exit
if args.contains('doc') {
if 'doc' in args {
// v.gen_doc_html_for_module(args.last())
exit(0)
}
@ -167,11 +163,11 @@ fn (v mut V) compile() {
}
// First pass (declarations)
for file in v.files {
mut p := v.new_parser(file, RUN_DECLS)
mut p := v.new_parser(file, Pass.decl)
p.parse()
}
// Main pass
cgen.run = RUN_MAIN
cgen.run = Pass.main
if v.pref.is_play {
cgen.genln('#define VPLAY (1) ')
}
@ -233,13 +229,13 @@ typedef map map_string;
#define false 0
#endif
//============================== HELPER C MACROS =============================*/
//============================== HELPER C.MACROS =============================*/
#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 _IN(typ, val, arr) array_##typ##_contains(arr, val)
#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 =================================*/
//int V_ZERO = 0;
@ -249,7 +245,7 @@ void reload_so();
void init_consts();')
imports_json := v.table.imports.contains('json')
// 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'))) {
cgen.genln('id defaultFont = 0; // main.v')
}
@ -284,7 +280,7 @@ void init_consts();')
cgen.genln('this line will be replaced with definitions')
defs_pos := cgen.lines.len - 1
for file in v.files {
mut p := v.new_parser(file, RUN_MAIN)
mut p := v.new_parser(file, Pass.main)
p.parse()
// p.g.gen_x64()
// Format all files (don't format automatically generated vlib headers)
@ -294,7 +290,7 @@ void init_consts();')
}
v.log('Done parsing.')
// 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.typedefs.join_lines())
d.writeln(cgen.types.join_lines())
@ -524,7 +520,7 @@ fn (c &V) cc_windows_cross() {
fn (v mut V) cc() {
// Cross compiling for Windows
if v.os == WINDOWS {
if v.os == .windows {
$if !windows {
v.cc_windows_cross()
return
@ -580,7 +576,7 @@ mut args := ''
}
// Cross compiling linux
sysroot := '/Users/alex/tmp/lld/linuxroot/'
if v.os == LINUX && !linux_host {
if v.os == .linux && !linux_host {
// Build file.o
a << '-c --sysroot=$sysroot -target x86_64-linux-gnu'
// Right now `out_name` can be `file`, not `file.o`
@ -597,17 +593,17 @@ mut args := ''
a << '"$TmpPath/$v.out_name_c"'
// }
// Min macos version is mandatory I think?
if v.os == MAC {
if v.os == .mac {
a << '-mmacosx-version-min=10.7'
}
a << flags
a << libs
// 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'
}
// 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'
}
// Find clang executable
@ -634,7 +630,7 @@ mut args := ''
panic('clang error')
}
// 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', '')
obj_file := v.out_name + '.o'
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') {
continue
}
if file.ends_with('_win.v') && v.os != WINDOWS {
if file.ends_with('_win.v') && v.os != .windows {
continue
}
if file.ends_with('_lin.v') && v.os != LINUX {
if file.ends_with('_lin.v') && v.os != .linux {
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')
// println('lin_file="$lin_file"')
// If there are both _mav.v and _lin.v, don't use _mav.v
if os.file_exists('$dir/$lin_file') {
continue
}
else if v.os == WINDOWS {
else if v.os == .windows {
continue
}
else {
@ -719,7 +715,7 @@ fn (v mut V) add_user_v_files() {
if is_test_with_imports {
user_files << dir
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') {
// Just compile one file and get parent dir
@ -743,7 +739,7 @@ fn (v mut V) add_user_v_files() {
}
// Parse user imports
for file in user_files {
mut p := v.new_parser(file, RUN_IMPORTS)
mut p := v.new_parser(file, Pass.imports)
p.parse()
}
// Parse lib imports
@ -753,7 +749,7 @@ fn (v mut V) add_user_v_files() {
vfiles := v.v_files_from_dir('$TmpPath/vlib/$pkg')
// Add all imports referenced by these libs
for file in vfiles {
mut p := v.new_parser(file, RUN_IMPORTS)
mut p := v.new_parser(file, Pass.imports)
p.parse()
}
}
@ -771,7 +767,7 @@ fn (v mut V) add_user_v_files() {
vfiles := v.v_files_from_dir(import_path)
// Add all imports referenced by these libs
for file in vfiles {
mut p := v.new_parser(file, RUN_IMPORTS)
mut p := v.new_parser(file, Pass.imports)
p.parse()
}
}
@ -890,24 +886,24 @@ fn new_v(args[]string) *V {
base := os.getwd().all_after('/')
out_name = base.trim_space()
}
mut _os := MAC
mut _os := OS.mac
// No OS specifed? Use current system
if target_os == '' {
$if linux {
_os = LINUX
_os = .linux
}
$if mac {
_os = MAC
_os = .mac
}
$if windows {
_os = WINDOWS
_os = .windows
}
}
else {
switch target_os {
case 'linux': _os = LINUX
case 'windows': _os = WINDOWS
case 'mac': _os = MAC
case 'linux': _os = .linux
case 'windows': _os = .windows
case 'mac': _os = .mac
}
}
builtins := [
@ -960,7 +956,7 @@ fn new_v(args[]string) *V {
mut f := '$lang_dir/vlib/builtin/$builtin'
// In default mode we use precompiled vlib.o, point to .vh files with signatures
if build_mode == .default_mode || build_mode == .build {
f = '$TmpPath/vlib/builtin/${builtin}h'
//f = '$TmpPath/vlib/builtin/${builtin}h'
}
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++
}
// 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
if s.pos >= s.text.len {
return scan_res(EOF, '')
return scan_res(.eof, '')
}
// skip whitespace
if !s.inside_string {
s.skip_whitespace()
}
if s.is_fmt && s.text[s.pos] == `\n` {
return scan_res(NL, '')
return scan_res(.nl, '')
}
// End of $var, start next string
if !s.is_fmt && s.dollar_end {
@ -190,16 +190,16 @@ fn (s mut Scanner) scan() ScanRes {
if s.text[s.pos] == SINGLE_QUOTE {
// fmt.Println("ENDDD")
s.dollar_end = false
return scan_res(STRING, '')
return scan_res(.strtoken, '')
}
s.dollar_end = false
return scan_res(STRING, s.ident_string())
return scan_res(.strtoken, s.ident_string())
}
s.skip_whitespace()
// end of file
if s.pos >= s.text.len {
// println('scan(): returning EOF (pos >= len)')
return scan_res(EOF, '')
// println('scan(): returning .eof (pos >= len)')
return scan_res(.eof, '')
}
// handle each char
c := s.text[s.pos]
@ -211,7 +211,7 @@ fn (s mut Scanner) scan() ScanRes {
if is_name_char(c) {
name := s.ident_name()
// 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` }
// println('!!! got name=$name next_char=$next_char')
if is_key(name) {
@ -232,7 +232,7 @@ fn (s mut Scanner) scan() ScanRes {
}
}
if s.dollar_start && next_char != `.` {
// println('INSIDE STRING .dollar var=$name')
// println('INSIDE .strtoken .dollar var=$name')
s.dollar_end = true
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
//Otherwise the scanner would be stuck at s.pos = 0
}
return scan_res(NAME, name)
return scan_res(.name, name)
}
// number, `.123`
else if c.is_digit() || c == `.` && nextc.is_digit() {
num := s.ident_number()
return scan_res(INT, num)
return scan_res(.integer, num)
}
// all other tokens
switch c {
case `+`:
if nextc == `+` {
s.pos++
return scan_res(INC, '')
return scan_res(.inc, '')
}
else if nextc == `=` {
s.pos++
return scan_res(PLUS_ASSIGN, '')
return scan_res(.plus_assign, '')
}
return scan_res(PLUS, '')
return scan_res(.plus, '')
case `-`:
if nextc == `-` {
s.pos++
return scan_res(DEC, '')
return scan_res(.dec, '')
}
else if nextc == `=` {
s.pos++
return scan_res(MINUS_ASSIGN, '')
return scan_res(.minus_assign, '')
}
return scan_res(MINUS, '')
return scan_res(.minus, '')
case `*`:
if nextc == `=` {
s.pos++
return scan_res(MULT_ASSIGN, '')
return scan_res(.mult_assign, '')
}
return scan_res(MUL, '')
return scan_res(.mul, '')
case `^`:
if nextc == `=` {
s.pos++
return scan_res(XOR_ASSIGN, '')
return scan_res(.xor_assign, '')
}
return scan_res(XOR, '')
return scan_res(.xor, '')
case `%`:
if nextc == `=` {
s.pos++
return scan_res(MOD_ASSIGN, '')
return scan_res(.mod_assign, '')
}
return scan_res(MOD, '')
return scan_res(.mod, '')
case `?`:
return scan_res(QUESTION, '')
return scan_res(.question, '')
case SINGLE_QUOTE:
return scan_res(STRING, s.ident_string())
return scan_res(.strtoken, s.ident_string())
// TODO allow double quotes
// case QUOTE:
// return scan_res(STRING, s.ident_string())
// return scan_res(.strtoken, s.ident_string())
case `\``:
return scan_res(CHAR, s.ident_char())
return scan_res(.chartoken, s.ident_char())
case `(`:
return scan_res(LPAR, '')
return scan_res(.lpar, '')
case `)`:
return scan_res(RPAR, '')
return scan_res(.rpar, '')
case `[`:
return scan_res(LSBR, '')
return scan_res(.lsbr, '')
case `]`:
return scan_res(RSBR, '')
return scan_res(.rsbr, '')
case `{`:
// Skip { in ${ in strings
if s.inside_string {
return s.scan()
}
return scan_res(LCBR, '')
return scan_res(.lcbr, '')
case `$`:
return scan_res(DOLLAR, '')
return scan_res(.dollar, '')
case `}`:
// s = `hello $name kek`
// s = `hello ${name} kek`
if s.inside_string {
s.pos++
// TODO UNNEEDED?
// TODO UN.neEDED?
if s.text[s.pos] == SINGLE_QUOTE {
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 {
return scan_res(RCBR, '')
return scan_res(.rcbr, '')
}
case `&`:
if nextc == `=` {
s.pos++
return scan_res(AND_ASSIGN, '')
return scan_res(.and_assign, '')
}
if nextc == `&` {
s.pos++
return scan_res(AND, '')
return scan_res(.and, '')
}
return scan_res(AMP, '')
return scan_res(.amp, '')
case `|`:
if nextc == `|` {
s.pos++
return scan_res(OR, '')
return scan_res(.ortok, '')
}
if nextc == `=` {
s.pos++
return scan_res(OR_ASSIGN, '')
return scan_res(.or_assign, '')
}
return scan_res(PIPE, '')
return scan_res(.pipe, '')
case `,`:
return scan_res(COMMA, '')
return scan_res(.comma, '')
case `\r`:
if nextc == `\n` {
s.pos++
return scan_res(NL, '')
return scan_res(.nl, '')
}
case `\n`:
return scan_res(NL, '')
return scan_res(.nl, '')
case `.`:
if nextc == `.` {
s.pos++
return scan_res(DOTDOT, '')
return scan_res(.dotdot, '')
}
return scan_res(DOT, '')
return scan_res(.dot, '')
case `#`:
start := s.pos + 1
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 #
s.pos--
}
return scan_res(HASH, hash.trim_space())
return scan_res(.hash, hash.trim_space())
case `>`:
if nextc == `=` {
s.pos++
return scan_res(GE, '')
return scan_res(.ge, '')
}
else if nextc == `>` {
if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` {
s.pos += 2
return scan_res(RIGHT_SHIFT_ASSIGN, '')
return scan_res(.righ_shift_assign, '')
}
s.pos++
return scan_res(RIGHT_SHIFT, '')
return scan_res(.righ_shift, '')
}
else {
return scan_res(GT, '')
return scan_res(.gt, '')
}
case `<`:
if nextc == `=` {
s.pos++
return scan_res(LE, '')
return scan_res(.le, '')
}
else if nextc == `<` {
if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` {
s.pos += 2
return scan_res(LEFT_SHIFT_ASSIGN, '')
return scan_res(.left_shift_assign, '')
}
s.pos++
return scan_res(LEFT_SHIFT, '')
return scan_res(.left_shift, '')
}
else {
return scan_res(LT, '')
return scan_res(.lt, '')
}
case `=`:
if nextc == `=` {
s.pos++
return scan_res(EQ, '')
return scan_res(.eq, '')
}
else {
return scan_res(ASSIGN, '')
return scan_res(.assign, '')
}
case `:`:
if nextc == `=` {
s.pos++
return scan_res(DECL_ASSIGN, '')
return scan_res(.decl_assign, '')
}
else {
return scan_res(COLON, '')
return scan_res(.colon, '')
}
case `;`:
return scan_res(SEMICOLON, '')
return scan_res(.semicolon, '')
case `!`:
if nextc == `=` {
s.pos++
return scan_res(NE, '')
return scan_res(.ne, '')
}
else {
return scan_res(NOT, '')
return scan_res(.not, '')
}
case `~`:
return scan_res(BIT_NOT, '')
return scan_res(.bit_not, '')
case `/`:
if nextc == `=` {
s.pos++
return scan_res(DIV_ASSIGN, '')
return scan_res(.div_assign, '')
}
if nextc == `/` {
// debug("!!!!!!GOT LINE COM")
// debug("!!!!!!.key_goT LI.ne COM")
start := s.pos + 1
for s.pos < s.text.len && s.text[s.pos] != `\n`{
s.pos++
@ -458,7 +458,7 @@ fn (s mut Scanner) scan() ScanRes {
// Skip comment
return s.scan()
}
return scan_res(LINE_COM, s.line_comment)
return scan_res(.line_com, s.line_comment)
}
// Multiline comments
if nextc == `*` {
@ -488,16 +488,16 @@ fn (s mut Scanner) scan() ScanRes {
comm := s.text.substr(start, end)
s.fgenln(comm)
if s.is_fmt {
return scan_res(MLINE_COM, comm)
return scan_res(.mline_com, comm)
}
// Skip if not in fmt mode
return s.scan()
}
return scan_res(DIV, '')
return scan_res(.div, '')
}
$if windows {
if c == `\0` {
return scan_res(EOF, '')
return scan_res(.eof, '')
}
}
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'
}
s.error(msg)
return scan_res(EOF, '')
return scan_res(.eof, '')
}
fn (s &Scanner) error(msg string) {
@ -637,7 +637,7 @@ fn (s mut Scanner) ident_char() string {
fn (p mut Parser) peek() Token {
for {
tok := p.scanner.peek()
if tok != NL {
if tok != .nl {
return tok
}
}
@ -681,7 +681,7 @@ fn (s mut Scanner) debug_tokens() {
println('')
}
// allToks += "\n"
if tok == EOF {
if tok == .eof {
println('============ END OF DEBUG TOKENS ==================')
// fmt.Println("========"+s.file+"========\n", allToks)
break

View File

@ -18,24 +18,25 @@ mut:
}
enum AccessMod {
PRIVATE // private immutable
PRIVET_MUT // private mutable
PUBLIC // public immmutable (readonly)
PUBLIC_MUT // public, but mutable 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)
private // private imkey_mut
private_mut // private key_mut
public // public immkey_mut (readonly)
public_mut // public, but key_mut only in this module
public_mut_mut // public and key_mut both inside and outside (not recommended to use, that's why it's so verbose)
}
struct Type {
mut:
pkg string
mod string
name string
fields []Var
methods []Fn
parent string
func Fn // For cat == FN (type kek fn())
is_c bool // C.FILE
is_c bool // C.FI.le
is_interface bool
is_enum bool
enum_vals []string
// 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.
// 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('u32', 'int')
t.register_type_with_parent('byte', 'int')
// t.register_type_with_parent('i64', 'int')
t.register_type('i64')
t.register_type_with_parent('i64', 'int')
t.register_type_with_parent('u64', 'int')
t.register_type('byteptr')
t.register_type('intptr')
@ -159,13 +159,13 @@ fn (table &Table) known_pkg(pkg string) bool {
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 {
name: name
typ: typ
is_const: true
is_import_const: is_imported
pkg: pkg
mod: mod
}
}
@ -176,7 +176,7 @@ fn (p mut Parser) register_global(name, typ string) {
typ: typ
is_const: 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 {
name: strtyp
parent: parent
pkg: p.pkg
mod: p.mod
}
p.table.register_type2(typ)
}
@ -297,6 +297,10 @@ fn (t &Type) has_field(name string) bool {
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 {
for field in t.fields {
if field.name == name {

View File

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