v/vlib/v/parser/comptime.v

261 lines
5.6 KiB
V
Raw Normal View History

2020-04-09 16:39:53 +02:00
// 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.
2020-02-10 14:42:57 +01:00
module parser
2020-02-17 14:15:42 +01:00
import os
2020-04-25 17:49:16 +02:00
import v.ast
import v.pref
import v.vmod
import v.table
2020-02-17 14:15:42 +01:00
2020-03-27 14:44:30 +01:00
const (
2020-04-09 16:39:53 +02:00
supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd',
'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos']
2020-03-27 14:44:30 +01:00
)
fn (mut p Parser) resolve_vroot(flag string) string {
mcache := vmod.get_cache()
vmod_file_location := mcache.get_by_folder(p.file_name_dir)
if vmod_file_location.vmod_file.len == 0 {
// There was no actual v.mod file found.
p.error('To use @VROOT, you need' + ' to have a "v.mod" file in ${p.file_name_dir},' +
' or in one of its parent folders.')
}
vmod_path := vmod_file_location.vmod_folder
return flag.replace('@VROOT', os.real_path(vmod_path))
}
2020-04-09 16:39:53 +02:00
// // #include, #flag, #v
2020-04-23 01:16:58 +02:00
fn (mut p Parser) hash() ast.HashStmt {
mut val := p.tok.lit
2020-04-09 16:39:53 +02:00
p.next()
2020-05-28 14:38:10 +02:00
if p.pref.backend == .js {
if !p.file_name.ends_with('.js.v') {
p.error('Hash statements are only allowed in backend specific files such "x.js.v"')
}
if p.mod == 'main' {
p.error('Hash statements are not allowed in the main module. Please place them in a separate module.')
}
}
if val.starts_with('include') {
mut flag := val[8..]
if flag.contains('@VROOT') {
vroot := p.resolve_vroot(flag)
val = 'include $vroot'
}
}
2020-04-09 16:39:53 +02:00
if val.starts_with('flag') {
// #flag linux -lm
mut flag := val[5..]
// expand `@VROOT` to its absolute path
if flag.contains('@VROOT') {
flag = p.resolve_vroot(flag)
2020-04-10 00:30:43 +02:00
}
2020-04-09 16:39:53 +02:00
for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] {
if flag.contains(deprecated) {
p.error('${deprecated} had been deprecated, use @VROOT instead.')
}
}
// println('adding flag "$flag"')
p.table.parse_cflag(flag, p.mod, p.pref.compile_defines_all) or {
p.error(err)
}
/*
words := val.split(' ')
if words.len > 1 && words[1] in supported_platforms {
if p.pref.os == .mac && words[1] == 'darwin' {
p.pref.cflags += val.after('darwin')
}
}
2020-04-25 17:49:16 +02:00
*/
2020-04-09 16:39:53 +02:00
}
return ast.HashStmt{
val: val
mod: p.mod
2020-04-09 16:39:53 +02:00
}
}
fn (mut p Parser) vweb() ast.ComptimeCall {
2020-05-27 03:33:37 +02:00
p.check(.dollar)
p.check(.name) // skip `vweb.html()` TODO
p.check(.dot)
p.check(.name)
p.check(.lpar)
p.check(.rpar)
return ast.ComptimeCall{}
}
fn (mut p Parser) comp_if() ast.Stmt {
2020-03-22 11:53:08 +01:00
pos := p.tok.position()
2020-02-17 14:15:42 +01:00
p.next()
2020-05-27 03:20:22 +02:00
// if p.tok.kind == .name && p.tok.lit == 'vweb' {
// return p.vweb()
// }
2020-02-17 14:15:42 +01:00
p.check(.key_if)
is_not := p.tok.kind == .not
if is_not {
2020-02-17 14:15:42 +01:00
p.next()
}
2020-03-22 13:55:39 +01:00
val := p.check_name()
mut stmts := []ast.Stmt{}
2020-03-27 14:44:30 +01:00
mut skip_os := false
if val in supported_platforms {
os := os_from_string(val)
// `$if os {` for a different target, skip everything inside
// to avoid compilation errors (like including <windows.h> or calling WinAPI fns
// on non-Windows systems)
if !p.pref.is_fmt && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) &&
2020-04-25 17:49:16 +02:00
!p.pref.output_cross_c {
2020-03-27 14:44:30 +01:00
skip_os = true
p.check(.lcbr)
// p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os')
2020-03-27 14:44:30 +01:00
mut stack := 1
2020-04-25 17:49:16 +02:00
for {
2020-03-27 14:44:30 +01:00
if p.tok.kind == .key_return {
p.returns = true
}
if p.tok.kind == .lcbr {
stack++
2020-04-09 16:39:53 +02:00
} else if p.tok.kind == .rcbr {
2020-03-27 14:44:30 +01:00
stack--
}
if p.tok.kind == .eof {
break
}
if stack <= 0 && p.tok.kind == .rcbr {
// p.warn('exiting $stack')
p.next()
break
}
p.next()
}
}
}
mut is_opt := false
2020-02-17 14:15:42 +01:00
if p.tok.kind == .question {
p.next()
is_opt = true
2020-02-17 14:15:42 +01:00
}
2020-03-27 14:44:30 +01:00
if !skip_os {
stmts = p.parse_block()
}
mut node := ast.CompIf{
is_not: is_not
is_opt: is_opt
2020-03-22 11:53:08 +01:00
pos: pos
2020-03-22 13:55:39 +01:00
val: val
2020-03-27 14:44:30 +01:00
stmts: stmts
}
2020-02-17 14:15:42 +01:00
if p.tok.kind == .dollar && p.peek_tok.kind == .key_else {
p.next()
p.next()
2020-03-22 14:54:31 +01:00
node.has_else = true
node.else_stmts = p.parse_block()
2020-02-17 14:15:42 +01:00
}
return node
2020-02-17 14:15:42 +01:00
}
2020-03-27 14:44:30 +01:00
2020-04-09 16:39:53 +02:00
// TODO import warning bug
const (
2020-04-09 16:39:53 +02:00
todo_delete_me = pref.OS.linux
)
2020-03-27 14:44:30 +01:00
fn os_from_string(os string) pref.OS {
match os {
'linux' {
return .linux
}
'windows' {
return .windows
}
'mac' {
return .mac
}
'macos' {
return .mac
}
'freebsd' {
return .freebsd
}
'openbsd' {
return .openbsd
}
'netbsd' {
return .netbsd
}
'dragonfly' {
return .dragonfly
}
'js' {
return .js
}
'solaris' {
return .solaris
}
'android' {
return .android
}
'msvc' {
// notice that `-os msvc` became `-cc msvc`
verror('use the flag `-cc msvc` to build using msvc')
}
'haiku' {
return .haiku
}
'linux_or_macos' {
return .linux
}
else {
panic('bad os $os')
}
}
// println('bad os $os') // todo panic?
return .linux
}
2020-05-27 03:20:22 +02:00
// `app.$action()` (`action` is a string)
// `typ` is `App` in this example
// fn (mut p Parser) comptime_method_call(typ table.Type) ast.ComptimeCall {
fn (mut p Parser) comptime_method_call(left ast.Expr) ast.ComptimeCall {
p.check(.dollar)
method_name := p.check_name()
2020-05-27 03:20:22 +02:00
/*
mut j := 0
sym := p.table.get_type_symbol(typ)
if sym.kind != .struct_ {
p.error('not a struct')
}
// info := sym.info as table.Struct
for method in sym.methods {
if method.return_type != table.void_type {
continue
}
/*
receiver := method.args[0]
if !p.expr_var.ptr {
p.error('`$p.expr_var.name` needs to be a reference')
}
amp := if receiver.is_mut && !p.expr_var.ptr { '&' } else { '' }
if j > 0 {
p.gen(' else ')
}
p.genln('if (string_eq($method_name, _STR("$method.name")) ) ' + '${typ.name}_$method.name ($amp $p.expr_var.name);')
*/
j++
}
2020-05-27 03:20:22 +02:00
*/
p.check(.lpar)
p.check(.rpar)
if p.tok.kind == .key_orelse {
p.check(.key_orelse)
// p.genln('else {')
p.check(.lcbr)
// p.statements()
}
2020-05-27 03:20:22 +02:00
return ast.ComptimeCall{
left: left
method_name: method_name
2020-05-27 03:20:22 +02:00
}
}