Skip to content

Commit 89e2684

Browse files
committed
keyword: replace cfunction with extern
1 parent 5e96760 commit 89e2684

File tree

9 files changed

+291
-196
lines changed

9 files changed

+291
-196
lines changed

compiler/compiler/compiler.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ func (c *Compiler) compile(instructions []parser.Node) {
250250
c.compileBreakNode(v)
251251
case *parser.ContinueNode:
252252
c.compileContinueNode(v)
253+
case *parser.ExternNode:
254+
for _, fn := range v.FuncNodes {
255+
c.compileDefineFuncNode(fn)
256+
}
253257

254258
case *parser.DeclarePackageNode:
255259
// TODO: Make use of it

compiler/compiler/func.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (c *Compiler) funcType(params, returnTypes []parser.TypeNode) (retType type
7878
// ABI description
7979
// method: package + _method_ + type + _ + name
8080
// named variable: package + name
81-
// cffi: function_name
81+
// cffi(extern): function_name
8282
// lambda: package + anonName
8383
func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) value.Value {
8484
var compiledName string
@@ -102,7 +102,7 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) value.Value {
102102
compiledName = c.currentPackageName + "_method_" + v.MethodOnType.TypeName + "_" + v.Name
103103
} else if v.IsNamed {
104104
// todo ffi set identifier
105-
if c.currentPackageName == "tx" {
105+
if v.IsExtern {
106106
compiledName = v.Name
107107
} else {
108108
compiledName = c.currentPackageName + "_" + v.Name
@@ -141,7 +141,7 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) value.Value {
141141
} else {
142142
fn = c.module.NewFunc(compiledName, funcRetType.LLVM(), llvmParams...)
143143
// register ffi function definnition for tx package and os package
144-
if v.IsCFunc {
144+
if v.IsExtern {
145145
// do not generate block
146146
} else {
147147
entry = fn.NewBlock(name.Block())
@@ -158,7 +158,7 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) value.Value {
158158

159159
// register ffi function definition for tx package
160160
// without generate func body
161-
if v.IsCFunc {
161+
if v.IsExtern {
162162
val := value.Value{
163163
Type: typesFunc,
164164
Value: fn,

compiler/lexer/keywords.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ var keywords = map[string]struct{}{
44
"if": {},
55
"else": {},
66
"func": {},
7-
"cfunction": {},
7+
"extern": {},
88
"return": {},
99
"type": {},
1010
"table": {},

compiler/parser/func.go

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package parser
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/cell-labs/cell-script/compiler/lexer"
8+
)
9+
10+
// DefineFuncNode creates a new named function
11+
type DefineFuncNode struct {
12+
baseNode
13+
14+
Name string
15+
IsNamed bool
16+
17+
IsMethod bool
18+
IsExtern bool
19+
20+
MethodOnType *SingleTypeNode
21+
IsPointerReceiver bool
22+
InstanceName string
23+
24+
Arguments []*NameNode
25+
ReturnValues []*NameNode
26+
Body []Node
27+
}
28+
29+
func (dfn DefineFuncNode) String() string {
30+
var body []string
31+
32+
for _, b := range dfn.Body {
33+
body = append(body, fmt.Sprintf("%+v", b))
34+
}
35+
36+
if dfn.IsMethod {
37+
return fmt.Sprintf("func+m (%+v) %s(%+v) %+v {\n\t%s\n}", dfn.InstanceName, dfn.Name, dfn.Arguments, dfn.ReturnValues, strings.Join(body, "\n\t"))
38+
} else if dfn.IsNamed {
39+
return fmt.Sprintf("func+n %s(%+v) %+v {\n\t%s\n}", dfn.Name, dfn.Arguments, dfn.ReturnValues, strings.Join(body, "\n\t"))
40+
} else {
41+
return fmt.Sprintf("func+v (%+v) %+v {\n\t%s\n}", dfn.Arguments, dfn.ReturnValues, strings.Join(body, "\n\t"))
42+
}
43+
}
44+
45+
type ExternNode struct {
46+
baseNode
47+
FuncNodes []*DefineFuncNode
48+
}
49+
50+
func (en ExternNode) String() string {
51+
var fns []string
52+
53+
for _, f := range en.FuncNodes {
54+
fns = append(fns, fmt.Sprintf("%+v", f.String()))
55+
}
56+
57+
return fmt.Sprintf("extern {\n\t%s\n}", strings.Join(fns, "\n\t"))
58+
}
59+
60+
func (p *parser) parseExtern() *ExternNode {
61+
// Single extern statement
62+
expectFuncString := p.lookAhead(0)
63+
if expectFuncString.Type == lexer.KEYWORD && expectFuncString.Val == "func" {
64+
p.i++
65+
dfn := p.parseFuncDefinition()
66+
dfn.IsExtern = true
67+
return &ExternNode{
68+
FuncNodes: []*DefineFuncNode{dfn},
69+
}
70+
}
71+
72+
fns := []*DefineFuncNode{}
73+
// Multiple extern
74+
p.expect(lexer.Item{Type: lexer.OPERATOR, Val: "("}, p.lookAhead(0))
75+
p.i++
76+
for {
77+
checkIfEndParen := p.lookAhead(0)
78+
if checkIfEndParen.Type == lexer.OPERATOR && checkIfEndParen.Val == ")" {
79+
break
80+
}
81+
if checkIfEndParen.Type == lexer.EOL {
82+
p.i++
83+
continue
84+
}
85+
86+
if checkIfEndParen.Type == lexer.KEYWORD && checkIfEndParen.Val == "func" {
87+
p.i++
88+
fn := p.parseFuncDefinition()
89+
fn.IsExtern = true
90+
fns = append(fns, fn)
91+
continue
92+
}
93+
94+
panic(fmt.Sprintf("Failed to parse extern: %+v", checkIfEndParen))
95+
}
96+
return &ExternNode{
97+
FuncNodes: fns,
98+
}
99+
}
100+
101+
// The tokens after keyword "func"
102+
func (p *parser) parseFuncDefinition() *DefineFuncNode {
103+
defineFunc := &DefineFuncNode{}
104+
var argsOrMethodType []*NameNode
105+
var canBeMethod bool
106+
107+
checkIfOpeningParen := p.lookAhead(0)
108+
if checkIfOpeningParen.Type == lexer.OPERATOR && checkIfOpeningParen.Val == "(" {
109+
p.i++
110+
argsOrMethodType = p.parseFunctionArguments()
111+
canBeMethod = true
112+
}
113+
114+
checkIfIdentifier := p.lookAhead(0)
115+
checkIfOpeningParen = p.lookAhead(1)
116+
117+
if canBeMethod && checkIfIdentifier.Type == lexer.IDENTIFIER &&
118+
checkIfOpeningParen.Type == lexer.OPERATOR && checkIfOpeningParen.Val == "(" {
119+
120+
defineFunc.IsMethod = true
121+
defineFunc.IsNamed = true
122+
defineFunc.Name = checkIfIdentifier.Val
123+
124+
if len(argsOrMethodType) != 1 {
125+
panic("Unexpected count of types in method")
126+
}
127+
128+
defineFunc.InstanceName = argsOrMethodType[0].Name
129+
130+
methodOnType := argsOrMethodType[0].Type
131+
132+
if pointerSingleTypeNode, ok := methodOnType.(*PointerTypeNode); ok {
133+
defineFunc.IsPointerReceiver = true
134+
methodOnType = pointerSingleTypeNode.ValueType
135+
}
136+
137+
if singleTypeNode, ok := methodOnType.(*SingleTypeNode); ok {
138+
defineFunc.MethodOnType = singleTypeNode
139+
} else {
140+
panic(fmt.Sprintf("could not find type in method defitition: %T", methodOnType))
141+
}
142+
}
143+
144+
name := p.lookAhead(0)
145+
openParen := p.lookAhead(1)
146+
if name.Type == lexer.IDENTIFIER && openParen.Type == lexer.OPERATOR && openParen.Val == "(" {
147+
defineFunc.Name = name.Val
148+
defineFunc.IsNamed = true
149+
150+
p.i++
151+
p.i++
152+
153+
// Parse argument list
154+
defineFunc.Arguments = p.parseFunctionArguments()
155+
} else {
156+
defineFunc.Arguments = argsOrMethodType
157+
}
158+
159+
// Parse return types
160+
var retTypesNodeNames []*NameNode
161+
162+
checkIfOpeningCurly := p.lookAhead(0)
163+
if checkIfOpeningCurly.Type != lexer.OPERATOR || checkIfOpeningCurly.Val != "{" {
164+
165+
// Check if next is an opening parenthesis
166+
// Is optional if there's only one return type, is required
167+
// if there is multiple ones
168+
var allowMultiRetVals bool
169+
170+
checkIfOpenParen := p.lookAhead(0)
171+
if checkIfOpenParen.Type == lexer.OPERATOR && checkIfOpenParen.Val == "(" {
172+
allowMultiRetVals = true
173+
p.i++
174+
}
175+
176+
for {
177+
nameNode := &NameNode{}
178+
179+
// Support both named return values and when we only get the type
180+
retTypeOrNamed, err := p.parseOneType()
181+
if err != nil {
182+
panic(err)
183+
}
184+
p.i++
185+
186+
// Next can be type, that means that the previous was the name of the var
187+
isType := p.lookAhead(0)
188+
if isType.Type == lexer.IDENTIFIER {
189+
retType, err := p.parseOneType()
190+
if err != nil {
191+
panic(err)
192+
}
193+
p.i++
194+
195+
nameNode.Name = retTypeOrNamed.Type()
196+
nameNode.Type = retType
197+
} else {
198+
nameNode.Type = retTypeOrNamed
199+
}
200+
201+
retTypesNodeNames = append(retTypesNodeNames, nameNode)
202+
203+
if !allowMultiRetVals {
204+
break
205+
}
206+
207+
// Check if comma or end parenthesis
208+
commaOrEnd := p.lookAhead(0)
209+
if commaOrEnd.Type == lexer.OPERATOR && commaOrEnd.Val == "," {
210+
p.i++
211+
continue
212+
}
213+
214+
if commaOrEnd.Type == lexer.OPERATOR && commaOrEnd.Val == ")" {
215+
p.i++
216+
break
217+
}
218+
panic("Could not parse function return types")
219+
}
220+
}
221+
222+
defineFunc.ReturnValues = retTypesNodeNames
223+
return defineFunc
224+
}

compiler/parser/node.go

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -180,41 +180,6 @@ func (ConditionNode) String() string {
180180
return "condition"
181181
}
182182

183-
// DefineFuncNode creates a new named function
184-
type DefineFuncNode struct {
185-
baseNode
186-
187-
Name string
188-
IsNamed bool
189-
190-
IsMethod bool
191-
IsCFunc bool
192-
193-
MethodOnType *SingleTypeNode
194-
IsPointerReceiver bool
195-
InstanceName string
196-
197-
Arguments []*NameNode
198-
ReturnValues []*NameNode
199-
Body []Node
200-
}
201-
202-
func (dfn DefineFuncNode) String() string {
203-
var body []string
204-
205-
for _, b := range dfn.Body {
206-
body = append(body, fmt.Sprintf("%+v", b))
207-
}
208-
209-
if dfn.IsMethod {
210-
return fmt.Sprintf("func+m (%+v) %s(%+v) %+v {\n\t%s\n}", dfn.InstanceName, dfn.Name, dfn.Arguments, dfn.ReturnValues, strings.Join(body, "\n\t"))
211-
} else if dfn.IsNamed {
212-
return fmt.Sprintf("func+n %s(%+v) %+v {\n\t%s\n}", dfn.Name, dfn.Arguments, dfn.ReturnValues, strings.Join(body, "\n\t"))
213-
} else {
214-
return fmt.Sprintf("func+v (%+v) %+v {\n\t%s\n}", dfn.Arguments, dfn.ReturnValues, strings.Join(body, "\n\t"))
215-
}
216-
}
217-
218183
// NameNode retreives a named variable
219184
type NameNode struct {
220185
baseNode

0 commit comments

Comments
 (0)