mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
new enum syntax; update the compiler (p.tok == .name
)
This commit is contained in:
parent
385f47c0cd
commit
26ef99293d
@ -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 {
|
||||
|
152
compiler/fn.v
152
compiler/fn.v
@ -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(')')
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
@ -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 {
|
||||
|
388
compiler/token.v
388
compiler/token.v
@ -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
|
||||
]
|
||||
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user