Skip to content

Commit

Permalink
Internal pragmas
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Oct 4, 2019
1 parent 5206020 commit 66e178e
Show file tree
Hide file tree
Showing 17 changed files with 142 additions and 58 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
nelua_cache
*.out
.vscode
tempCodeRunner.*
tempCodeRunner.*
neluacfg.lua
2 changes: 1 addition & 1 deletion examples/condots.nelua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
!!strict
## strict = true

## if EMSCRIPTEN then
--TODO: default output file as html for emcc
Expand Down
6 changes: 3 additions & 3 deletions examples/snakesdl.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

-- import SDL headers
!!strict
!!cdefine 'SDL_DISABLE_IMMINTRIN_H'
!!cinclude '<SDL2/SDL.h>'
!!linklib 'SDL2'
!!cdefine('SDL_DISABLE_IMMINTRIN_H')
!!cinclude('<SDL2/SDL.h>')
!!linklib('SDL2')

-- import SDL structures
local SDL_Event !cimport = @record {
Expand Down
6 changes: 3 additions & 3 deletions lib/math.nelua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## state.strict = true
## state.modname = 'nelua'
## state.nohashcodenames = true
## strict = true
## modname = 'nelua'
## nohashcodenames = true

--TODO: function type overload

Expand Down
6 changes: 3 additions & 3 deletions lib/memory.nelua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## state.strict = true
## state.modname = 'nelua'
## state.nohashcodenames = true
## strict = true
## modname = 'nelua'
## nohashcodenames = true

!!cinclude '<stdlib.h>'
!!cinclude '<string.h>'
Expand Down
2 changes: 1 addition & 1 deletion lib/mystring.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
--TODO: varargs
--TODO: optional parameters/returns

## state.modname = 'mystring'
## modname = 'mystring'

--------------------------------------------------------------------------------
-- C imports
Expand Down
11 changes: 11 additions & 0 deletions nelua/astdefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ astbuilder:register('Attrib', {
stypes.array_of(ntypes.String + ntypes.Number + ntypes.Boolean) -- args
})

-- used inerally internal
astbuilder:register('PragmaCall', {
stypes.string, -- name
stypes.table, -- args exprs
})

astbuilder:register('PragmaSet', {
stypes.string, -- name
stypes.any, -- value
})

-- identifier and types
astbuilder:register('Id', {
stypes.string + ntypes.PreprocessName, -- name
Expand Down
5 changes: 5 additions & 0 deletions nelua/cgenerator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ end

-- TODO: Function

function visitors.PragmaSet(context, node)
local name, value = node:args()
context[name] = value
end

function visitors.Attrib(context, node, emitter)
local attr = node.attr
if attr.cinclude then
Expand Down
2 changes: 1 addition & 1 deletion nelua/configer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ local function init_default_configs()
end

local function load_home_configs()
local homeconfigfile = fs.join(fs.getuserconfpath(), '.nelua.lua')
local homeconfigfile = fs.getuserconfpath('neluacfg.lua')
if not fs.isfile(homeconfigfile) then return end
local homeconfig = dofile(homeconfigfile)
tabler.update(defconfig, homeconfig)
Expand Down
2 changes: 1 addition & 1 deletion nelua/context.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ local function traverser_default_visitor(self, node, ...)
end

function Context:_init(visitors, default_visitor, parentcontext)
self.state = {}
if parentcontext then
self.rootscope = parentcontext.rootscope
self.builtins = parentcontext.builtins
Expand All @@ -52,6 +51,7 @@ function Context:_init(visitors, default_visitor, parentcontext)
elseif default_visitor then
self.default_visitor = default_visitor
end
self.strict = false
self.nodes = {}
end

Expand Down
66 changes: 49 additions & 17 deletions nelua/preprocessor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ function PPContext:_init(context, visitors)
self.registry = {}
end

function PPContext:push_statnodes()
local statnodes = {oldstatnodes = self.statnodes}
self.statnodes = statnodes
return statnodes
end

function PPContext:pop_statnodes()
self.statnodes = self.statnodes.oldstatnodes
end

function PPContext:add_statnode(node)
table.insert(self.statnodes, node)
self.context:traverse(node)
end

function PPContext.toname(_, val, orignode)
orignode:assertraisef(traits.is_string(val),
'unable to convert preprocess value of type "%s" to a compile time name', type(val))
Expand Down Expand Up @@ -154,7 +169,7 @@ function visitors.Block(ppcontext, node, emitter, parent)
node.needprocess = false

emitter:add_ln('do')
emitter:add_ln('local ppnewstatnodes = {}')
emitter:add_ln('local ppnewstatnodes = ppcontext:push_statnodes()')
emitter:add_ln('ppregistry[', ppcontext:getregistryindex(node), '][1] = ppnewstatnodes')
emitter:add_ln('context:push_scope("block")')
for _,statnode in ipairs(statnodes) do
Expand All @@ -164,12 +179,11 @@ function visitors.Block(ppcontext, node, emitter, parent)
emitter:add_ln('do')
emitter:add_ln('local ppstatnode = ppregistry[', ppcontext:getregistryindex(statnode), ']')
ppcontext:traverse(statnode, emitter)
emitter:add_ln('local ppnewstatnode = ppstatnode:clone()')
emitter:add_ln('table.insert(ppnewstatnodes, ppnewstatnode)')
emitter:add_ln('context:traverse(ppnewstatnode)')
emitter:add_ln('ppcontext:add_statnode(ppstatnode:clone())')
emitter:add_ln('end')
end
end
emitter:add_ln('ppcontext:pop_statnodes()')
emitter:add_ln('context:pop_scope()')
emitter:add_ln('end')
end
Expand Down Expand Up @@ -212,6 +226,17 @@ function marker_visitors.Block(markercontext, node)
end
end

local ppenvgetfields = {}
function ppenvgetfields:scope()
return self.context.scope
end
function ppenvgetfields:ast()
return self.context:get_top_node()
end
function ppenvgetfields:symbols()
return self.context.scope.symbols
end

local preprocessor = {}
function preprocessor.preprocess(context, ast)
assert(ast.tag == 'Block')
Expand All @@ -230,30 +255,37 @@ function preprocessor.preprocess(context, ast)

-- second pass, emit the preprocess lua code
local ppcontext = PPContext(context, visitors)
local aster = context.astbuilder.aster
local emitter = Emitter(ppcontext, 0)
emitter:add_ln("local ppcontext = ppcontext")
emitter:add_ln("local ppregistry = ppcontext.registry")
emitter:add_ln("local context = ppcontext.context")
ppcontext:traverse(ast, emitter)

-- generate the preprocess function
local ppcode = emitter:generate()
local env = setmetatable({
local env
env = setmetatable({
context = context,
aster = context.astbuilder.aster,
ppcontext = ppcontext,
ppregistry = ppcontext.registry
aster = aster,
addnode = function(node) ppcontext:add_statnode(node) end,
config = config
}, { __index = function(_, key)
if key == 'scope' then
return context.scope
elseif key == 'ast' then
return context:get_top_node()
elseif key == 'symbols' then
return context.scope.symbols
elseif key == 'state' then
return context.state
elseif key == 'config' then
return config
local ppenvfield = ppenvgetfields[key]
if ppenvfield then
return ppenvfield(env)
elseif typedefs.field_pragmas[key] then
return context[key]
else
return _G[key]
end
end, __newindex = function(_, key, value)
if typedefs.field_pragmas[key] then
ppcontext:add_statnode(aster.PragmaSet{key, value})
else
env[key] = value
end
end})

-- try to run the preprocess otherwise capture and show the error
Expand Down
8 changes: 4 additions & 4 deletions nelua/scope.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function Scope:get_symbol(name, node, required)
end
end
end
if not symbol and required and self.context.state.strict and not self.context.preprocessing then
if not symbol and required and self.context.strict and not self.context.preprocessing then
node:raisef("undeclared symbol '%s'", name)
end
return symbol
Expand All @@ -83,7 +83,7 @@ function Scope:add_symbol(symbol)
assert(name)
local oldsymbol = self.symbols[name]
if oldsymbol and (not oldsymbol.node or oldsymbol.node ~= symbol.node) then
symbol.node:assertraisef(not self.context.state.strict,
symbol.node:assertraisef(not self.context.strict,
"symbol '%s' shadows pre declared symbol with the same name", name)

if rawget(self.symbols, name) == oldsymbol then
Expand All @@ -93,8 +93,8 @@ function Scope:add_symbol(symbol)

symbol.attr.shadowed = true
end
if self.context.state.modname then
symbol.attr.modname = self.context.state.modname
if self.context.modname then
symbol.attr.modname = self.context.modname
end
self.symbols[name] = symbol
return symbol
Expand Down
21 changes: 14 additions & 7 deletions nelua/typechecker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ function visitors.Table(context, node, desiredtype)
end
end

function visitors.PragmaSet(context, node)
local name, value = node:args()
local pragmashape = typedefs.field_pragmas[name]
node:assertraisef(pragmashape, "pragma '%s' is not defined", name)
context[name] = value
end

function visitors.Attrib(context, node, symbol)
--TODO: quick return

Expand Down Expand Up @@ -287,7 +294,7 @@ function visitors.Attrib(context, node, symbol)
end
end
if name == 'strict' then
context.state.strict = true
context.strict = true
end
end

Expand Down Expand Up @@ -379,8 +386,8 @@ function visitors.TypeInstance(context, node, _, symbol)

if symbol and not attr.holdedtype:is_primitive() then
local prefix
if context.state.nohashcodenames then
prefix = context.state.modname or context.ast.modname
if context.nohashcodenames then
prefix = context.modname or context.ast.modname
end
attr.holdedtype:suggest_nick(symbol.name, prefix)
end
Expand Down Expand Up @@ -1122,7 +1129,7 @@ function visitors.VarDecl(context, node)
varnode:assertraisef(context.scope:is_static_storage(), 'global variables can only be declared in top scope')
varnode.attr.global = true
end
if context.state.nostatic then
if context.nostatic then
varnode.attr.nostatic = true
end
local symbol = context:traverse(varnode)
Expand Down Expand Up @@ -1157,7 +1164,7 @@ function visitors.VarDecl(context, node)
valnode.attr.initializer = true
end
else
if context.state.noinit then
if context.noinit then
varnode.attr.noinit = true
end
end
Expand Down Expand Up @@ -1618,10 +1625,10 @@ function typechecker.analyze(ast, parser, parentcontext)
end)

-- forward global attributes to ast
if context.state.nocore then
if context.nocore then
ast.attr.nocore = true
end
if context.state.nofloatsuffix then
if context.nofloatsuffix then
ast.attr.nofloatsuffix = true
end

Expand Down
19 changes: 19 additions & 0 deletions nelua/typedefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,25 @@ typedefs.block_attribs = {
strict = true
}

typedefs.call_pragmas = {
cinclude = shaper.shape{shaper.string},
cemit = shaper.shape{shaper.string, shaper.string:is_optional()},
cdefine = shaper.shape{shaper.string},
cflags = shaper.shape{shaper.string},
ldflags = shaper.shape{shaper.string},
linklib = shaper.shape{shaper.string},
}

typedefs.field_pragmas = {
strict = shaper.shape{shaper.boolean},
nohashcodenames = shaper.shape{shaper.boolean},
noinit = shaper.shape{shaper.boolean},
nostatic = shaper.shape{shaper.boolean},
nofloatsuffix = shaper.shape{shaper.boolean},
nocore = shaper.shape{shaper.boolean},
modname = shaper.shape{shaper.string},
}

local common_attribs = {
cimport = shaper.shape{shaper.string:is_optional(), (shaper.boolean + shaper.string):is_optional()},
onestring = shaper.shape{shaper.string},
Expand Down
4 changes: 2 additions & 2 deletions nelua/utils/fs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ function fs.getdatapath(arg0)
return path
end

function fs.getuserconfpath()
return plpath.expanduser('~')
function fs.getuserconfpath(filename)
return plpath.expanduser(fs.join('~', '.config', 'nelua', filename))
end

function fs.findmodulefile(name, path)
Expand Down
Loading

0 comments on commit 66e178e

Please sign in to comment.