Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIFC implementation, WIP #15

Merged
merged 10 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 35 additions & 23 deletions doc/nifc-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ or not!) are encoded via this table:
| `>` | `gtQ` |
| `~` | `tildeQ` |
| `:` | `colonQ` |
| `.` | `dotQ` |
| `@` | `atQ` |
| `| ` | `barQ` |
| Other | `XxxQ` where `xx` is the hexadecimal value |
Expand All @@ -86,6 +85,7 @@ Lvalue ::= Symbol | (deref Expr) |
(dot Expr Symbol Number) | # field access
(pat Expr Expr) | # pointer indexing

Call ::= (call Expr+ )
Expr ::= Number | CharLiteral | StringLiteral |
Lvalue |
(par Expr) | # wraps the expression in parentheses
Expand All @@ -95,9 +95,8 @@ Expr ::= Number | CharLiteral | StringLiteral |
(or Expr Expr) | # "||"
(not Expr) | # "!"
(sizeof Expr) |
(constr Type Expr*) |
(kv Expr Expr) |

(oconstr Type (kv Symbol Expr)*) | # (object constructor){...}
(aconstr Type Expr*) | # array constructor
(add Type Expr Expr) |
(sub Type Expr Expr) |
(mul Type Expr Expr) |
Expand All @@ -108,12 +107,14 @@ Expr ::= Number | CharLiteral | StringLiteral |
(bitand Type Expr Expr) |
(bitor Type Expr Expr) |
(bitnot Type Expr Expr) |
(bitxor Type Expr Expr) |
(eq Expr Expr) |
(neq Expr Expr) |
(le Expr Expr) |
(lt Expr Expr) |
(cast Type Expr) |
(call Expr+ )
(conv Type Expr) |
Call

BranchValue ::= Number | CharLiteral | Symbol
BranchRange ::= BranchValue | (range BranchValue BranchValue)
Expand All @@ -123,7 +124,7 @@ VarDecl ::= (var SymbolDef VarPragmas Type [Empty | Expr])
ConstDecl ::= (const SymbolDef VarPragmas Type Expr)
EmitStmt ::= (emit Expr+)

Stmt ::= Expr |
Stmt ::= Call |
VarDecl |
ConstDecl |
EmitStmt |
Expand All @@ -133,12 +134,11 @@ Stmt ::= Expr |
(case Expr (of BranchRanges StmtList)* (else StmtList)?) |
(lab SymbolDef) |
(jmp Symbol) |
(tjmp Expr Symbol) | # jump if condition is true
(fjmp Expr Symbol) | # jump if condition is false
(ret Expr) # return statement

StmtList ::= (stmts Stmt*)

Param ::= (param SymbolDef ParamPragmas Type)
Params ::= Empty | (params Param*)

ProcDecl ::= (proc SymbolDef Params Type ProcPragmas [Empty | StmtList])
Expand All @@ -147,7 +147,7 @@ FieldDecl ::= (fld SymbolDef FieldPragmas Type)

UnionDecl ::= (union Empty FieldDecl*)
ObjDecl ::= (object [Empty | Type] FieldDecl*)
EnumFieldDecl ::= (efld SymbolDef Expr)
EnumFieldDecl ::= (efld SymbolDef Number)
EnumDecl ::= (enum Type EnumFieldDecl+)

ProcType ::= (proctype Empty Params Type ProcTypePragmas)
Expand All @@ -163,15 +163,17 @@ Type ::= Symbol |
(bool IntQualifier*) |
(void) |
(ptr Type PtrQualifier) | # pointer to a single object
(array Type Expr) |
(flexarray Type) |
(aptr Type PtrQualifier) | # pointer to an array of objects
ProcType
TypeDecl ::= (type SymbolDef TypePragmas [Type | ObjDecl | UnionDecl | EnumDecl])
ArrayDecl ::= (array Type Expr)
TypeDecl ::= (type SymbolDef TypePragmas [ProcType | ObjDecl | UnionDecl | EnumDecl | ArrayDecl])

CallingConvention ::= (cdecl) | (stdcall) | (safecall) | (syscall) |
(fastcall) | (thiscall) | (noconv) | (member)

CallingConvention ::= (cdecl) | (stdcall)
Attribute ::= (attr StringLiteral)
ProcPragma ::= (inline) | CallingConvention | (varargs) | (was Identifier) |
ProcPragma ::= (inline) | (noinline) | CallingConvention | (varargs) | (was Identifier) |
(selectany) | Attribute
ProcTypePragma ::= CallingConvention | (varargs) | Attribute

Expand All @@ -182,6 +184,9 @@ CommonPragma ::= (align Number) | (was Identifier) | Attribute
VarPragma ::= CommonPragma | (tls)
VarPragmas ::= Empty | (pragmas VarPragma+)

ParamPragma ::= (was Identifier) | Attribute
ParamPragmas ::= Empty | (pragmas ParamPragma+)

FieldPragma ::= CommonPragma | (bits Number)
FieldPragmas ::= (pragmas FieldPragma+)

Expand All @@ -190,11 +195,12 @@ TypePragmas ::= Empty | (pragmas TypePragma+)


ExternDecl ::= (imp ProcDecl | VarDecl | ConstDecl)

TopLevelConstruct ::= ExternDecl | ProcDecl | VarDecl | ConstDecl |
TypeDecl | EmitStmt
IgnoreDecl ::= (nodecl ProcDecl | VarDecl | ConstDecl)
Include ::= (incl StringLiteral)
Module ::= (stmts Include* TopLevelConstruct*)

TopLevelConstruct ::= ExternDecl | IngoreDecl | ProcDecl | VarDecl | ConstDecl |
TypeDecl | Include | EmitStmt
Module ::= (stmts TopLevelConstruct*)

```

Expand All @@ -205,8 +211,6 @@ Notes:
- There can be more calling conventions than only `cdecl` and `stdcall`.
- `case` is mapped to a `switch` but the generation of `break` is handled
automatically.
- `constr` is an array or union or object constructor. For this case `Expr` was
extended to cover the item `kv` (which is a key-value pair).
- `ro` stands for `readonly` and is C's notion of the `const` type qualifier.
Not to be confused with NIFC's `const` which introduces a named constant.
- C allows for `typedef` within proc bodies. NIFC does not, a type declaration must
Expand All @@ -228,6 +232,17 @@ Notes:
- `attr "abc"` annotates a symbol with `__attribute__(abc)`.
- `cast` might be mapped to a type prunning operation via a `union` as C's aliasing
rules are broken.
- `conv` is a value preserving type conversion between numeric types, `cast` is a bit
preserving type cast.
- `array` is mapped to a struct with an array inside so that arrays gain value semantics.
Hence arrays can only be used within a `type` environment and are nominal types.
A NIFC code generator has to ensure that e.g. `(type :MyArray.T . (array T 4))` is only
emitted once.
- `type` can only be used to introduce a name for a nominal type (that is a type which
is only compatible to itself) or for a proc type for code compression purposes. Arbitrary
aliases for types **cannot** be used! Rationale: Implementation simplicity.
- `nodecl` is an import mechanism like `imp` but the declarations come from a header file
and are not to be declared in the resulting C/C++ code.


Inheritance
Expand All @@ -246,7 +261,4 @@ and RTTI must be implemented manually, if required.
Declaration order
-----------------

It is currently not specified whether NIFC allows for an arbitrary order of declarations
without the need for forward declarations. It might be easier for a generator to produce
the declarations in a suitable order rather than burdening the NIFC to C translator with
such a reorder task.
NIFC allows for an arbitrary order of declarations without the need for forward declarations.
Binary file modified doc/nifc-spec.pdf
Binary file not shown.
9 changes: 9 additions & 0 deletions src/lib/nifbuilder.nim
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ proc addHeader*(b: var Builder; vendor = "", dialect = "") =
b.addStrLit dialect
b.put ")\n"

proc addFlags*[T: enum](b: var Builder; kind: string; flags: set[T]) =
## Little helper for converting a set of enum to NIF. If `flags` is
## the empty set, nothing is emitted.
if flags == {}:
discard "omit empty flags in order to save space"
else:
withTree b, kind:
for x in items(flags):
b.addIdent $x

when isMainModule:
proc test(b: sink Builder) =
Expand Down
2 changes: 2 additions & 0 deletions src/lib/nifreader.nim
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,15 @@ proc open*(filename: string): Reader =
if not err:
result.p = cast[pchar](result.f.mem)
result.eof = result.p +! result.f.size
result.lineStart = result.p

proc openFromBuffer*(buf: sink string): Reader =
result = Reader(f: default(MemFile), err: true, buf: ensureMove buf)
result.p = cast[pchar](addr result.buf[0])
result.eof = result.p +! result.buf.len
result.f.mem = result.p
result.f.size = result.buf.len
result.lineStart = result.p

proc close*(r: var Reader) =
if not r.err: close r.f
Expand Down
42 changes: 42 additions & 0 deletions src/lib/packedtrees.nim
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,13 @@ proc hasAtLeastXsons*[E](tree: PackedTree[E]; n: NodePos; x: int): bool =
return false

proc firstSon*[E](tree: PackedTree[E]; n: NodePos): NodePos {.inline.} =
assert tree[n].kind.isTree
assert n.int <= int(n) + tree[n].rawSpan
NodePos(n.int+1)

template check[E](a: int; tree: PackedTree[E]; n: NodePos) =
assert a < int(n) + int(n) + tree[n].rawSpan

proc kind*[E](tree: PackedTree[E]; n: NodePos): E {.inline.} =
tree.nodes[n.int].kind

Expand All @@ -166,16 +172,47 @@ proc span*[E](tree: PackedTree[E]; pos: int): int {.inline.} =
proc sons2*[E](tree: PackedTree[E]; n: NodePos): (NodePos, NodePos) =
assert(not isAtom(tree, n.int))
let a = n.int+1
check a, tree, n
let b = a + span(tree, a)
check b, tree, n
result = (NodePos a, NodePos b)

proc sons3*[E](tree: PackedTree[E]; n: NodePos): (NodePos, NodePos, NodePos) =
assert(not isAtom(tree, n.int))
let a = n.int+1
check a, tree, n
let b = a + span(tree, a)
check b, tree, n
let c = b + span(tree, b)
check c, tree, n
result = (NodePos a, NodePos b, NodePos c)

proc sons4*[E](tree: PackedTree[E]; n: NodePos): (NodePos, NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
check a, tree, n
let b = a + span(tree, a)
check b, tree, n
let c = b + span(tree, b)
check c, tree, n
let d = c + span(tree, c)
check d, tree, n
result = (NodePos a, NodePos b, NodePos c, NodePos d)

proc sons5*[E](tree: PackedTree[E]; n: NodePos): (NodePos, NodePos, NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
check a, tree, n
let b = a + span(tree, a)
check b, tree, n
let c = b + span(tree, b)
check c, tree, n
let d = c + span(tree, c)
check d, tree, n
let e = d + span(tree, d)
check e, tree, n
result = (NodePos a, NodePos b, NodePos c, NodePos d, NodePos e)

proc ithSon*[E](tree: PackedTree[E]; n: NodePos; i: int): NodePos =
result = default(NodePos)
if tree.nodes[n.int].kind.isTree:
Expand All @@ -185,8 +222,13 @@ proc ithSon*[E](tree: PackedTree[E]; n: NodePos; i: int): NodePos =
inc count
assert false, "node has no i-th child"

const
StartPos* = NodePos(0)

proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)

proc currentPos*[E](tree: PackedTree[E]): NodePos {.inline.} = NodePos(tree.nodes.len)

template copyIntoFrom*(dest, n, body) =
let patchPos = prepare(dest, tree, n)
body
Expand Down
Loading