mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v2: consts, $if, attributes, globals, if/for type check, prefs
This commit is contained in:
parent
7808f4c272
commit
d87cb3f672
@ -81,10 +81,10 @@ pub fn eprintln(s string) {
|
||||
panic('eprintln(NIL)')
|
||||
}
|
||||
$if !windows {
|
||||
C.fflush(stdout)
|
||||
C.fflush(stderr)
|
||||
C.fprintf(stderr, '%.*s\n', s.len, s.str)
|
||||
C.fflush(stderr)
|
||||
C.fflush(C.stdout)
|
||||
C.fflush(C.stderr)
|
||||
C.fprintf(C.stderr, '%.*s\n', s.len, s.str)
|
||||
C.fflush(C.stderr)
|
||||
return
|
||||
}
|
||||
// TODO issues with stderr and cross compiling for Linux
|
||||
@ -96,10 +96,10 @@ pub fn eprint(s string) {
|
||||
panic('eprint(NIL)')
|
||||
}
|
||||
$if !windows {
|
||||
C.fflush(stdout)
|
||||
C.fflush(stderr)
|
||||
C.fprintf(stderr, '%.*s', s.len, s.str)
|
||||
C.fflush(stderr)
|
||||
C.fflush(C.stdout)
|
||||
C.fflush(C.stderr)
|
||||
C.fprintf(C.stderr, '%.*s', s.len, s.str)
|
||||
C.fflush(C.stderr)
|
||||
return
|
||||
}
|
||||
print(s)
|
||||
@ -124,6 +124,8 @@ pub fn print(s string) {
|
||||
__global total_m i64=0
|
||||
__global nr_mallocs int=0
|
||||
|
||||
fn looo(){} // TODO remove, [ pratt
|
||||
|
||||
[unsafe_fn]
|
||||
pub fn malloc(n int) byteptr {
|
||||
if n <= 0 {
|
||||
|
@ -8,12 +8,12 @@ import (
|
||||
v.table
|
||||
)
|
||||
|
||||
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral |
|
||||
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
|
||||
pub type Expr = InfixExpr | IfExpr | StringLiteral | IntegerLiteral |
|
||||
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr | PostfixExpr |
|
||||
AssignExpr | PrefixExpr | MethodCallExpr | IndexExpr | RangeExpr
|
||||
|
||||
pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt |
|
||||
ForStmt | StructDecl | ForCStmt | ForInStmt
|
||||
pub type Stmt = VarDecl | GlobalDecl | FnDecl | Return | Module | Import | ExprStmt |
|
||||
ForStmt | StructDecl | ForCStmt | ForInStmt | CompIf | ConstDecl | Attr
|
||||
// | IncDecStmt k
|
||||
// Stand-alone expression in a statement list.
|
||||
pub struct ExprStmt {
|
||||
@ -63,7 +63,13 @@ pub struct Field {
|
||||
pub:
|
||||
name string
|
||||
// type_idx int
|
||||
ti table.Type
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct ConstDecl {
|
||||
pub:
|
||||
fields []Field
|
||||
exprs []Expr
|
||||
}
|
||||
|
||||
pub struct StructDecl {
|
||||
@ -159,6 +165,14 @@ mut:
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct GlobalDecl {
|
||||
pub:
|
||||
name string
|
||||
expr Expr
|
||||
mut:
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct File {
|
||||
pub:
|
||||
mod Module
|
||||
@ -178,6 +192,7 @@ type IdentInfo = IdentVar
|
||||
pub enum IdentKind {
|
||||
blank_ident
|
||||
variable
|
||||
constant
|
||||
}
|
||||
|
||||
// A single identifier
|
||||
@ -232,6 +247,7 @@ pub:
|
||||
// op token.Kind
|
||||
left Expr
|
||||
index Expr // [0], [start..end] etc
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct IfExpr {
|
||||
@ -242,12 +258,21 @@ pub:
|
||||
else_stmts []Stmt
|
||||
ti table.Type
|
||||
left Expr // `a` in `a := if ...`
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct CompIf {
|
||||
pub:
|
||||
cond Expr
|
||||
stmts []Stmt
|
||||
else_stmts []Stmt
|
||||
}
|
||||
|
||||
pub struct ForStmt {
|
||||
pub:
|
||||
cond Expr
|
||||
stmts []Stmt
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct ForInStmt {
|
||||
@ -280,6 +305,11 @@ pub:
|
||||
}
|
||||
*/
|
||||
|
||||
// e.g. `[unsafe_fn]`
|
||||
pub struct Attr {
|
||||
pub:
|
||||
name string
|
||||
}
|
||||
|
||||
pub struct AssignExpr {
|
||||
pub:
|
||||
|
@ -68,6 +68,9 @@ pub fn (c &Checker) infix_expr(infix_expr ast.InfixExpr) table.Type {
|
||||
// c.error('infix expr: cannot use `$infix_expr.right_type.name` as `$infix_expr.left_type.name`', infix_expr.pos)
|
||||
c.error('infix expr: cannot use `$left_ti.name` as `$right_ti.name`', infix_expr.pos)
|
||||
}
|
||||
if infix_expr.op.is_relational() {
|
||||
return table.bool_type
|
||||
}
|
||||
return left_ti
|
||||
}
|
||||
|
||||
@ -195,111 +198,120 @@ fn (c &Checker) stmt(node ast.Stmt) {
|
||||
ast.VarDecl {
|
||||
typ := c.expr(it.expr)
|
||||
// println('var decl $typ.name it.typ=$it.typ.name $it.pos.line_nr')
|
||||
if it.typ.kind == .unresolved {
|
||||
// it.ti = typ
|
||||
// println('unresolved var')
|
||||
}
|
||||
// if it.typ.kind == .unresolved {
|
||||
// it.ti = typ
|
||||
// println('unresolved var')
|
||||
// }
|
||||
}
|
||||
ast.ForStmt {
|
||||
typ := c.expr(it.cond)
|
||||
if typ.kind != .bool {
|
||||
c.error('non-bool used as for condition', it.pos)
|
||||
}
|
||||
ast.ForStmt {
|
||||
c.expr(it.cond)
|
||||
for stmt in it.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
for stmt in it.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
ast.ForCStmt {
|
||||
c.stmt(it.init)
|
||||
c.expr(it.cond)
|
||||
c.stmt(it.inc)
|
||||
for stmt in it.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
}
|
||||
ast.ForCStmt {
|
||||
c.stmt(it.init)
|
||||
c.expr(it.cond)
|
||||
c.stmt(it.inc)
|
||||
for stmt in it.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
// ast.StructDecl {}
|
||||
ast.ExprStmt {
|
||||
c.expr(it.expr)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
// ast.StructDecl {}
|
||||
ast.ExprStmt {
|
||||
c.expr(it.expr)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
match node {
|
||||
ast.AssignExpr {
|
||||
c.check_assign_expr(it)
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
return table.int_type
|
||||
}
|
||||
// ast.FloatLiteral {}
|
||||
ast.PostfixExpr {
|
||||
return c.expr(it.expr)
|
||||
}
|
||||
/*
|
||||
pub fn (c &Checker) expr(node ast.Expr) table.Type {
|
||||
match node {
|
||||
ast.AssignExpr {
|
||||
c.check_assign_expr(it)
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
return table.int_type
|
||||
}
|
||||
// ast.FloatLiteral {}
|
||||
ast.PostfixExpr {
|
||||
return c.expr(it.expr)
|
||||
}
|
||||
/*
|
||||
ast.UnaryExpr {
|
||||
c.expr(it.left)
|
||||
}
|
||||
*/
|
||||
|
||||
ast.StringLiteral {
|
||||
return table.string_type
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
return c.expr(it.right)
|
||||
}
|
||||
ast.InfixExpr {
|
||||
return c.infix_expr(it)
|
||||
}
|
||||
ast.StructInit {
|
||||
return c.check_struct_init(it)
|
||||
}
|
||||
ast.CallExpr {
|
||||
return c.call_expr(it)
|
||||
}
|
||||
ast.MethodCallExpr {
|
||||
return c.check_method_call_expr(it)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
return c.array_init(it)
|
||||
}
|
||||
ast.Ident {
|
||||
if it.kind == .variable {
|
||||
info := it.info as ast.IdentVar
|
||||
if info.typ.kind != .unresolved {
|
||||
return info.typ
|
||||
}
|
||||
return c.expr(info.expr)
|
||||
ast.StringLiteral {
|
||||
return table.string_type
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
return c.expr(it.right)
|
||||
}
|
||||
ast.InfixExpr {
|
||||
return c.infix_expr(it)
|
||||
}
|
||||
ast.StructInit {
|
||||
return c.check_struct_init(it)
|
||||
}
|
||||
ast.CallExpr {
|
||||
return c.call_expr(it)
|
||||
}
|
||||
ast.MethodCallExpr {
|
||||
return c.check_method_call_expr(it)
|
||||
}
|
||||
ast.ArrayInit {
|
||||
return c.array_init(it)
|
||||
}
|
||||
ast.Ident {
|
||||
if it.kind == .variable {
|
||||
info := it.info as ast.IdentVar
|
||||
if info.typ.kind != .unresolved {
|
||||
return info.typ
|
||||
}
|
||||
return table.void_type
|
||||
return c.expr(info.expr)
|
||||
}
|
||||
// ast.BoolLiteral {}
|
||||
ast.SelectorExpr {
|
||||
return c.selector_expr(it)
|
||||
return table.void_type
|
||||
}
|
||||
ast.BoolLiteral {
|
||||
return table.bool_type
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
return c.selector_expr(it)
|
||||
}
|
||||
ast.IndexExpr {
|
||||
// c.expr(it.left)
|
||||
// c.expr(it.index)
|
||||
return it.typ
|
||||
}
|
||||
ast.IfExpr {
|
||||
typ := c.expr(it.cond)
|
||||
if typ.kind != .bool {
|
||||
c.error('non-bool (`$typ.name`) used as if condition', it.pos)
|
||||
}
|
||||
ast.IndexExpr {
|
||||
c.expr(it.left)
|
||||
c.expr(it.index)
|
||||
for i, stmt in it.stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
ast.IfExpr {
|
||||
c.expr(it.cond)
|
||||
for i, stmt in it.stmts {
|
||||
if it.else_stmts.len > 0 {
|
||||
for stmt in it.else_stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
if it.else_stmts.len > 0 {
|
||||
for stmt in it.else_stmts {
|
||||
c.stmt(stmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
return table.void_type
|
||||
}
|
||||
else {}
|
||||
}
|
||||
return table.void_type
|
||||
}
|
||||
|
||||
pub fn (c &Checker) error(s string, pos token.Position) {
|
||||
print_backtrace()
|
||||
final_msg_line := '$c.file_name:$pos.line_nr: error: $s'
|
||||
eprintln(final_msg_line)
|
||||
/*
|
||||
pub fn (c &Checker) error(s string, pos token.Position) {
|
||||
print_backtrace()
|
||||
final_msg_line := '$c.file_name:$pos.line_nr: error: $s'
|
||||
eprintln(final_msg_line)
|
||||
/*
|
||||
if colored_output {
|
||||
eprintln(term.bold(term.red(final_msg_line)))
|
||||
}else{
|
||||
@ -307,5 +319,5 @@ fn (c &Checker) stmt(node ast.Stmt) {
|
||||
}
|
||||
*/
|
||||
|
||||
exit(1)
|
||||
}
|
||||
exit(1)
|
||||
}
|
||||
|
@ -51,6 +51,13 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||
// g.writeln('//// stmt start')
|
||||
match node {
|
||||
ast.Import {}
|
||||
ast.ConstDecl {
|
||||
for i, field in it.fields {
|
||||
g.write('$field.typ.name $field.name = ')
|
||||
g.expr(it.exprs[i])
|
||||
g.writeln(';')
|
||||
}
|
||||
}
|
||||
ast.FnDecl {
|
||||
g.fn_decl = &it
|
||||
is_main := it.name == 'main'
|
||||
@ -145,7 +152,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
|
||||
g.writeln('typedef struct {')
|
||||
for field in it.fields {
|
||||
// t := g.table.get_type(field.ti.idx)
|
||||
ti := g.table.refresh_ti(field.ti)
|
||||
ti := g.table.refresh_ti(field.typ)
|
||||
g.writeln('\t$ti.name $field.name;')
|
||||
}
|
||||
g.writeln('} $it.name;')
|
||||
|
@ -6,6 +6,8 @@ multi_return_int_string multi_return();
|
||||
void variadic(variadic_int a);
|
||||
void ensure_cap(int required, int cap);
|
||||
|
||||
int pi = 3;
|
||||
|
||||
typedef struct {
|
||||
int age;
|
||||
} User;
|
||||
@ -19,6 +21,7 @@ int main() {
|
||||
a++;
|
||||
foo(3);
|
||||
int ak = 10;
|
||||
int mypi = pi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
import moda
|
||||
import modb as mb
|
||||
|
||||
const (
|
||||
pi = 3
|
||||
//s = 'hi'
|
||||
|
||||
)
|
||||
|
||||
struct User {
|
||||
age int
|
||||
}
|
||||
@ -15,6 +21,7 @@ fn main() {
|
||||
a++
|
||||
foo(3)
|
||||
ak := 10
|
||||
mypi := pi
|
||||
}
|
||||
/*
|
||||
user := User{}
|
||||
|
@ -50,7 +50,7 @@ pub fn (p mut Parser) call_args() []ast.Expr {
|
||||
return args // ,table.void_ti
|
||||
}
|
||||
|
||||
fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
fn (p mut Parser) fn_decl(/*high bool*/) ast.FnDecl {
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
p.next()
|
||||
@ -68,14 +68,18 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
if p.tok.kind == .key_mut {
|
||||
p.next()
|
||||
}
|
||||
rec_ti = p.parse_ti()
|
||||
rec_ti = p.parse_type()
|
||||
p.table.register_var(table.Var{
|
||||
name: rec_name
|
||||
typ: rec_ti
|
||||
})
|
||||
p.check(.rpar)
|
||||
}
|
||||
name := p.check_name()
|
||||
mut name := ''
|
||||
if p.tok.kind == .name {
|
||||
// TODO
|
||||
name = p.check_name()
|
||||
}
|
||||
// println('fn decl $name')
|
||||
p.check(.lpar)
|
||||
// Args
|
||||
@ -88,7 +92,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
p.check(.comma)
|
||||
arg_names << p.check_name()
|
||||
}
|
||||
ti := p.parse_ti()
|
||||
ti := p.parse_type()
|
||||
for arg_name in arg_names {
|
||||
arg := table.Var{
|
||||
name: arg_name
|
||||
@ -112,7 +116,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
// Return type
|
||||
mut typ := table.void_type
|
||||
if p.tok.kind in [.name, .lpar] {
|
||||
typ = p.parse_ti()
|
||||
typ = p.parse_type()
|
||||
p.return_type = typ
|
||||
}
|
||||
else {
|
||||
@ -144,7 +148,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
|
||||
is_pub: is_pub
|
||||
receiver: ast.Field{
|
||||
name: rec_name
|
||||
ti: rec_ti
|
||||
typ: rec_ti
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type {
|
||||
if p.tok.kind == .number {
|
||||
size := p.tok.lit.int()
|
||||
p.check(.rsbr)
|
||||
elem_ti := p.parse_ti()
|
||||
elem_ti := p.parse_type()
|
||||
idx,name := p.table.find_or_register_array_fixed(&elem_ti, size, 1)
|
||||
return table.new_type(.array_fixed, name, idx, nr_muls)
|
||||
}
|
||||
// array
|
||||
p.check(.rsbr)
|
||||
elem_ti := p.parse_ti()
|
||||
elem_ti := p.parse_type()
|
||||
mut nr_dims := 1
|
||||
for p.tok.kind == .lsbr {
|
||||
p.check(.lsbr)
|
||||
@ -33,9 +33,9 @@ pub fn (p mut Parser) parse_array_ti(nr_muls int) table.Type {
|
||||
pub fn (p mut Parser) parse_map_ti(nr_muls int) table.Type {
|
||||
p.next()
|
||||
p.check(.lsbr)
|
||||
key_ti := p.parse_ti()
|
||||
key_ti := p.parse_type()
|
||||
p.check(.rsbr)
|
||||
value_ti := p.parse_ti()
|
||||
value_ti := p.parse_type()
|
||||
idx,name := p.table.find_or_register_map(&key_ti, &value_ti)
|
||||
return table.new_type(.map, name, idx, nr_muls)
|
||||
}
|
||||
@ -44,7 +44,7 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type {
|
||||
p.check(.lpar)
|
||||
mut mr_tis := []table.Type
|
||||
for {
|
||||
mr_ti := p.parse_ti()
|
||||
mr_ti := p.parse_type()
|
||||
mr_tis << mr_ti
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
@ -60,12 +60,18 @@ pub fn (p mut Parser) parse_multi_return_ti() table.Type {
|
||||
|
||||
pub fn (p mut Parser) parse_variadic_ti() table.Type {
|
||||
p.check(.ellipsis)
|
||||
variadic_ti := p.parse_ti()
|
||||
variadic_ti := p.parse_type()
|
||||
idx,name := p.table.find_or_register_variadic(&variadic_ti)
|
||||
return table.new_type(.variadic, name, idx, 0)
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) parse_ti() table.Type {
|
||||
pub fn (p mut Parser) parse_fn_type() table.Type {
|
||||
//p.check(.key_fn)
|
||||
p.fn_decl()
|
||||
return table.int_type
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) parse_type() table.Type {
|
||||
mut nr_muls := 0
|
||||
for p.tok.kind == .amp {
|
||||
p.check(.amp)
|
||||
@ -73,6 +79,10 @@ pub fn (p mut Parser) parse_ti() table.Type {
|
||||
}
|
||||
name := p.tok.lit
|
||||
match p.tok.kind {
|
||||
// func
|
||||
.key_fn {
|
||||
return p.parse_fn_type()
|
||||
}
|
||||
// array
|
||||
.lsbr {
|
||||
return p.parse_array_ti(nr_muls)
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
v.ast
|
||||
v.token
|
||||
v.table
|
||||
v.pref
|
||||
term
|
||||
os
|
||||
)
|
||||
@ -35,6 +36,9 @@ mut:
|
||||
//
|
||||
// prefix_parse_fns []PrefixParseFn
|
||||
inside_if bool
|
||||
pref &pref.Preferences // Preferences shared from V struct
|
||||
builtin_mod bool
|
||||
mod string
|
||||
}
|
||||
|
||||
// for tests
|
||||
@ -59,6 +63,8 @@ pub fn parse_file(path string, table &table.Table) ast.File {
|
||||
scanner: scanner.new_scanner(text)
|
||||
table: table
|
||||
file_name: path
|
||||
pref: &pref.Preferences{}
|
||||
builtin_mod: true
|
||||
}
|
||||
p.read_first_token()
|
||||
// module decl
|
||||
@ -170,6 +176,12 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
|
||||
// }
|
||||
}
|
||||
}
|
||||
.lsbr {
|
||||
return p.attr()
|
||||
}
|
||||
.key_global {
|
||||
return p.global_decl()
|
||||
}
|
||||
.key_const {
|
||||
return p.const_decl()
|
||||
}
|
||||
@ -179,16 +191,12 @@ pub fn (p mut Parser) top_stmt() ast.Stmt {
|
||||
.key_struct {
|
||||
return p.struct_decl()
|
||||
}
|
||||
.lsbr {
|
||||
p.next()
|
||||
p.check(.name)
|
||||
p.check(.rsbr)
|
||||
return ast.Module{}
|
||||
.dollar {
|
||||
return p.comp_if()
|
||||
}
|
||||
else {
|
||||
p.error('bad top level statement')
|
||||
return ast.Module{} // silence C warning
|
||||
// exit(0)
|
||||
return ast.Stmt{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -204,6 +212,9 @@ pub fn (p mut Parser) stmt() ast.Stmt {
|
||||
.key_return {
|
||||
return p.return_stmt()
|
||||
}
|
||||
.dollar {
|
||||
return p.comp_if()
|
||||
}
|
||||
else {
|
||||
// `x := ...`
|
||||
if p.tok.kind == .name && p.peek_tok.kind == .decl_assign {
|
||||
@ -218,6 +229,22 @@ pub fn (p mut Parser) stmt() ast.Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) comp_if() ast.CompIf {
|
||||
p.next()
|
||||
p.check(.key_if)
|
||||
if p.tok.kind == .not {
|
||||
p.next()
|
||||
}
|
||||
p.check_name()
|
||||
p.parse_block()
|
||||
if p.tok.kind == .dollar && p.peek_tok.kind == .key_else {
|
||||
p.next()
|
||||
p.check(.key_else)
|
||||
p.parse_block()
|
||||
}
|
||||
return ast.CompIf{}
|
||||
}
|
||||
|
||||
pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr {
|
||||
op := p.tok.kind
|
||||
p.next()
|
||||
@ -231,6 +258,15 @@ pub fn (p mut Parser) assign_expr(left ast.Expr) ast.AssignExpr {
|
||||
return node
|
||||
}
|
||||
|
||||
fn (p mut Parser) attr() ast.Attr {
|
||||
p.check(.lsbr)
|
||||
name := p.check_name()
|
||||
p.check(.rsbr)
|
||||
return ast.Attr{
|
||||
name: name
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) range_expr(low ast.Expr) ast.Expr {
|
||||
// ,table.Type) {
|
||||
p.next()
|
||||
@ -310,7 +346,8 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
||||
mut node := ast.Expr{}
|
||||
// mut typ := table.void_ti
|
||||
mut typ := table.unresolved_type
|
||||
if p.tok.lit == 'C' {
|
||||
is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
|
||||
if is_c {
|
||||
p.next()
|
||||
p.check(.dot)
|
||||
}
|
||||
@ -327,7 +364,7 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
||||
}
|
||||
// struct init
|
||||
else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || p.tok.lit in ['array', 'string']) {
|
||||
typ = p.parse_ti()
|
||||
typ = p.parse_type()
|
||||
// p.warn('struct init typ=$typ.name')
|
||||
p.check(.lcbr)
|
||||
mut field_names := []string
|
||||
@ -347,13 +384,13 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
||||
}
|
||||
p.check(.rcbr)
|
||||
}
|
||||
// variable
|
||||
else {
|
||||
// p.warn('name ')
|
||||
// left := p.parse_ident()
|
||||
mut ident := ast.Ident{
|
||||
name: p.tok.lit
|
||||
}
|
||||
// variable
|
||||
if var := p.table.find_var(p.tok.lit) {
|
||||
typ = var.typ
|
||||
ident.kind = .variable
|
||||
@ -361,18 +398,40 @@ pub fn (p mut Parser) name_expr() (ast.Expr,table.Type) {
|
||||
typ: typ
|
||||
name: ident.name
|
||||
// expr: p.expr(0)// var.expr
|
||||
|
||||
|
||||
}
|
||||
// ident.ti = ti
|
||||
node = ident
|
||||
p.next()
|
||||
}else{
|
||||
// Function object (not a call), e.g. `onclick(my_click)`
|
||||
p.table.find_fn(p.tok.lit) or {
|
||||
p.error('name expr unknown variable `$p.tok.lit`')
|
||||
exit(0)
|
||||
if is_c {
|
||||
typ = table.int_type
|
||||
ident.info = ast.IdentVar{
|
||||
typ: typ
|
||||
name: ident.name
|
||||
}
|
||||
node = ident
|
||||
p.next()
|
||||
return node,typ
|
||||
}
|
||||
// const
|
||||
if c := p.table.find_const(p.tok.lit) {
|
||||
typ = c.typ
|
||||
ident.kind = .constant
|
||||
ident.info = ast.IdentVar{
|
||||
typ: typ
|
||||
name: ident.name
|
||||
}
|
||||
node = ident
|
||||
p.next()
|
||||
}else{
|
||||
// Function object (not a call), e.g. `onclick(my_click)`
|
||||
p.table.find_fn(p.tok.lit) or {
|
||||
p.error('name expr unknown identifier `$p.tok.lit`')
|
||||
exit(0)
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
return node,typ
|
||||
@ -505,6 +564,7 @@ fn (p mut Parser) index_expr(left ast.Expr, typ_ table.Type) (ast.Expr,table.Typ
|
||||
node = ast.IndexExpr{
|
||||
left: left
|
||||
index: index_expr
|
||||
typ: typ
|
||||
}
|
||||
// return node
|
||||
return node,typ
|
||||
@ -572,6 +632,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
stmts := p.parse_block()
|
||||
return ast.ForStmt{
|
||||
stmts: stmts
|
||||
pos: p.tok.position()
|
||||
}
|
||||
}
|
||||
else if p.tok.kind == .key_mut {
|
||||
@ -600,9 +661,6 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
if p.tok.kind != .semicolon {
|
||||
mut typ := table.Type{}
|
||||
cond,typ = p.expr(0)
|
||||
if typ.kind != .bool {
|
||||
p.error('non-bool used as for condition')
|
||||
}
|
||||
}
|
||||
p.check(.semicolon)
|
||||
if p.tok.kind != .lcbr {
|
||||
@ -630,6 +688,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
// println('nr stmts=$stmts.len')
|
||||
return ast.ForStmt{
|
||||
stmts: stmts
|
||||
pos: p.tok.position()
|
||||
}
|
||||
}
|
||||
// `for cond {`
|
||||
@ -641,6 +700,7 @@ fn (p mut Parser) for_statement() ast.Stmt {
|
||||
return ast.ForStmt{
|
||||
cond: cond
|
||||
stmts: stmts
|
||||
pos: p.tok.position()
|
||||
}
|
||||
}
|
||||
|
||||
@ -650,12 +710,8 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
|
||||
// }
|
||||
mut node := ast.Expr{}
|
||||
p.check(.key_if)
|
||||
cond,cond_ti := p.expr(0)
|
||||
cond,_ := p.expr(0)
|
||||
p.inside_if = false
|
||||
// if !p.table.check(table.bool_ti, cond_ti) {
|
||||
if cond_ti.kind != .bool {
|
||||
p.error('non-bool (`$cond_ti.name`) used as if condition')
|
||||
}
|
||||
stmts := p.parse_block()
|
||||
mut else_stmts := []ast.Stmt
|
||||
if p.tok.kind == .key_else {
|
||||
@ -679,8 +735,9 @@ fn (p mut Parser) if_expr() (ast.Expr,table.Type) {
|
||||
stmts: stmts
|
||||
else_stmts: else_stmts
|
||||
ti: ti
|
||||
pos: p.tok.position()
|
||||
// left: left
|
||||
|
||||
|
||||
}
|
||||
return node,ti
|
||||
}
|
||||
@ -708,19 +765,19 @@ fn (p mut Parser) string_expr() (ast.Expr,table.Type) {
|
||||
|
||||
fn (p mut Parser) array_init() (ast.Expr,table.Type) {
|
||||
p.check(.lsbr)
|
||||
mut val_ti := table.void_type
|
||||
mut val_type := table.void_type
|
||||
mut exprs := []ast.Expr
|
||||
for i := 0; p.tok.kind != .rsbr; i++ {
|
||||
expr,ti := p.expr(0)
|
||||
expr,typ := p.expr(0)
|
||||
exprs << expr
|
||||
if i == 0 {
|
||||
val_ti = ti
|
||||
val_type = typ
|
||||
}
|
||||
if p.tok.kind == .comma {
|
||||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
type_idx,type_name := p.table.find_or_register_array(val_ti, 1)
|
||||
type_idx,type_name := p.table.find_or_register_array(val_type, 1)
|
||||
array_ti := table.new_type(.array, type_name, type_idx, 0)
|
||||
mut node := ast.Expr{}
|
||||
node = ast.ArrayInit{
|
||||
@ -792,20 +849,31 @@ fn (p mut Parser) import_stmt() []ast.Import {
|
||||
return imports
|
||||
}
|
||||
|
||||
// TODO
|
||||
// fn (p mut Parser) const_decl() ast... {
|
||||
fn (p mut Parser) const_decl() ast.Stmt {
|
||||
fn (p mut Parser) const_decl() ast.ConstDecl {
|
||||
p.check(.key_const)
|
||||
p.check(.lpar)
|
||||
mut fields := []ast.Field
|
||||
mut exprs := []ast.Expr
|
||||
for p.tok.kind != .rpar {
|
||||
name := p.check_name()
|
||||
println('const: $name')
|
||||
p.check(.assign)
|
||||
_,_ := p.expr(0)
|
||||
// expr, ti := p.expr(0)
|
||||
expr,typ := p.expr(0)
|
||||
fields << ast.Field{
|
||||
name: name
|
||||
typ: typ
|
||||
}
|
||||
exprs << expr
|
||||
p.table.register_const(table.Var{
|
||||
name: name
|
||||
typ: typ
|
||||
})
|
||||
}
|
||||
p.check(.rpar)
|
||||
return ast.Stmt{}
|
||||
return ast.ConstDecl{
|
||||
fields: fields
|
||||
exprs: exprs
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||
@ -824,15 +892,15 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
|
||||
p.check(.colon)
|
||||
}
|
||||
field_name := p.check_name()
|
||||
ti := p.parse_ti()
|
||||
ti := p.parse_type()
|
||||
ast_fields << ast.Field{
|
||||
name: field_name
|
||||
ti: ti
|
||||
typ: ti
|
||||
}
|
||||
fields << table.Field{
|
||||
name: field_name
|
||||
// type_idx: ti.idx
|
||||
|
||||
|
||||
ti: ti
|
||||
}
|
||||
}
|
||||
@ -905,7 +973,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
|
||||
name: name
|
||||
is_mut: is_mut
|
||||
// expr: expr
|
||||
|
||||
|
||||
typ: typ
|
||||
})
|
||||
p.warn('var decl name=$name typ=$typ.name')
|
||||
@ -913,7 +981,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
|
||||
node := ast.VarDecl{
|
||||
name: name
|
||||
expr: expr // p.expr(token.lowest_prec)
|
||||
|
||||
|
||||
is_mut: is_mut
|
||||
typ: typ
|
||||
pos: p.tok.position()
|
||||
@ -921,6 +989,40 @@ fn (p mut Parser) var_decl() ast.VarDecl {
|
||||
return node
|
||||
}
|
||||
|
||||
fn (p mut Parser) global_decl() ast.GlobalDecl {
|
||||
if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
|
||||
p.error('use `v --enable-globals ...` to enable globals')
|
||||
}
|
||||
p.next()
|
||||
name := p.check_name()
|
||||
println(name)
|
||||
typ := p.parse_type()
|
||||
if p.tok.kind == .assign {
|
||||
p.next()
|
||||
p.expr(0)
|
||||
}
|
||||
p.table.register_global(name, typ)
|
||||
// p.genln(p.table.cgen_name_type_pair(name, typ))
|
||||
/*
|
||||
mut g := p.table.cgen_name_type_pair(name, typ)
|
||||
if p.tok == .assign {
|
||||
p.next()
|
||||
g += ' = '
|
||||
_,expr := p.tmp_expr()
|
||||
g += expr
|
||||
}
|
||||
// p.genln('; // global')
|
||||
g += '; // global'
|
||||
if !p.cgen.nogen {
|
||||
p.cgen.consts << g
|
||||
}
|
||||
*/
|
||||
|
||||
return ast.GlobalDecl{
|
||||
name: name
|
||||
}
|
||||
}
|
||||
|
||||
fn verror(s string) {
|
||||
println(s)
|
||||
exit(1)
|
||||
|
68
vlib/v/pref/pref.v
Normal file
68
vlib/v/pref/pref.v
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module pref
|
||||
|
||||
pub enum BuildMode {
|
||||
// `v program.v'
|
||||
// Build user code only, and add pre-compiled vlib (`cc program.o builtin.o os.o...`)
|
||||
default_mode
|
||||
// `v -lib ~/v/os`
|
||||
// build any module (generate os.o + os.vh)
|
||||
build_module
|
||||
}
|
||||
|
||||
|
||||
pub struct Preferences {
|
||||
pub mut:
|
||||
build_mode BuildMode
|
||||
// nofmt bool // disable vfmt
|
||||
is_test bool // `v test string_test.v`
|
||||
is_script bool // single file mode (`v program.v`), main function can be skipped
|
||||
is_live bool // main program that contains live/hot code
|
||||
is_solive bool // a shared library, that will be used in a -live main program
|
||||
is_so bool // an ordinary shared library, -shared, no matter if it is live or not
|
||||
is_prof bool // benchmark every function
|
||||
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
|
||||
is_prod bool // use "-O2"
|
||||
is_verbose bool // print extra information with `v.log()`
|
||||
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
|
||||
is_repl bool
|
||||
is_run bool
|
||||
show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c
|
||||
sanitize bool // use Clang's new "-fsanitize" option
|
||||
is_debug bool // false by default, turned on by -g or -cg, it tells v to pass -g to the C backend compiler.
|
||||
is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly).
|
||||
is_keep_c bool // -keep_c , tell v to leave the generated .tmp.c alone (since by default v will delete them after c backend finishes)
|
||||
// NB: passing -cg instead of -g will set is_vlines to false and is_g to true, thus making v generate cleaner C files,
|
||||
// which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks).
|
||||
is_pretty_c bool // -pretty_c , tell v to run clang-format -i over the produced C file, before it is compiled. Use with -keep_c or with -o x.c .
|
||||
is_cache bool // turns on v usage of the module cache to speed up compilation.
|
||||
is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run
|
||||
no_auto_free bool // `v -nofree` disable automatic `free()` insertion for better performance in some applications (e.g. compilers)
|
||||
cflags string // Additional options which will be passed to the C compiler.
|
||||
// For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size.
|
||||
// You could pass several -cflags XXX arguments. They will be merged with each other.
|
||||
// You can also quote several options at the same time: -cflags '-Os -fno-inline-small-functions'.
|
||||
ccompiler string // the name of the used C compiler
|
||||
building_v bool
|
||||
autofree bool
|
||||
compress bool
|
||||
// skip_builtin bool // Skips re-compilation of the builtin module
|
||||
// to increase compilation time.
|
||||
// This is on by default, since a vast majority of users do not
|
||||
// work on the builtin module itself.
|
||||
// generating_vh bool
|
||||
fast bool // use tcc/x64 codegen
|
||||
enable_globals bool // allow __global for low level code
|
||||
// is_fmt bool
|
||||
is_bare bool
|
||||
user_mod_path string // `v -user_mod_path /Users/user/modules` adds a new lookup path for imported modules
|
||||
vlib_path string
|
||||
vpath string
|
||||
x64 bool
|
||||
output_cross_c bool
|
||||
prealloc bool
|
||||
v2 bool
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ pub mut:
|
||||
local_vars []Var
|
||||
// fns Hashmap
|
||||
fns map[string]Fn
|
||||
consts map[string]Var
|
||||
tmp_cnt int
|
||||
imports []string
|
||||
}
|
||||
@ -27,11 +28,13 @@ pub:
|
||||
|
||||
pub struct Var {
|
||||
pub:
|
||||
name string
|
||||
is_mut bool
|
||||
name string
|
||||
is_mut bool
|
||||
is_const bool
|
||||
is_global bool
|
||||
// expr ast.Expr
|
||||
mut:
|
||||
typ Type
|
||||
typ Type
|
||||
}
|
||||
|
||||
pub fn new_table() &Table {
|
||||
@ -78,6 +81,23 @@ pub fn (t mut Table) clear_vars() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (t mut Table) register_const(v Var) {
|
||||
t.consts[v.name] = v
|
||||
}
|
||||
|
||||
pub fn (t mut Table) register_global(name string, typ Type) {
|
||||
t.consts[name] = Var{
|
||||
name: name
|
||||
typ: typ
|
||||
is_const: true
|
||||
is_global: true
|
||||
// mod: p.mod
|
||||
// is_mut: true
|
||||
// idx: -1
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (t mut Table) register_var(v Var) {
|
||||
println('register_var: $v.name - $v.typ.name')
|
||||
t.local_vars << v
|
||||
@ -112,6 +132,15 @@ pub fn (t &Table) find_fn(name string) ?Fn {
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (t &Table) find_const(name string) ?Var {
|
||||
f := t.consts[name]
|
||||
if f.name.str != 0 {
|
||||
// TODO
|
||||
return f
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (t mut Table) register_fn(new_fn Fn) {
|
||||
// println('reg fn $new_fn.name nr_args=$new_fn.args.len')
|
||||
t.fns[new_fn.name] = new_fn
|
||||
@ -351,7 +380,7 @@ pub fn (t &Table) check(got, expected &Type) bool {
|
||||
// if expected.name == 'array' {
|
||||
// return true
|
||||
// }
|
||||
if got.idx != expected.idx {
|
||||
if got.idx != expected.idx && got.name != expected.name {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
Loading…
Reference in New Issue
Block a user