Skip to content

Commit

Permalink
go语言函数调用使用::
Browse files Browse the repository at this point in the history
  • Loading branch information
CheungChan committed May 9, 2022
1 parent 3269192 commit f40676b
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 27 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ https://github.com/CheungChan/duang/releases
demo里面支持的语法现在都支持。

## 程序运行输出截图:
![](https://img.azhangbaobao.cn/img/20220506020204.png)
![](https://img.azhangbaobao.cn/img/20220509141847.png)

## 语法设想
1. 既有`python`的可读性
Expand Down
27 changes: 26 additions & 1 deletion duang/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,39 @@ func (a *FunctionCall) Dump(prefix string) {
}
fmt.Printf("%s FunctionCall %s %s\n", prefix, a.name, r)
for _, x := range a.parameters {
fmt.Printf("%s\tparameters: %s\n", prefix, x)
fmt.Printf("%s\tparameters: %#v\n", prefix, x)
}
}

func (a *FunctionCall) accept(visitor AstVisitor) interface{} {
return visitor.VisitFunctionCall(a)
}

type GoFunctionCall struct {
AstNode
name string
parameters []Expression
}

func NewGoFunctionCall(name string, parameters []Expression) *GoFunctionCall {
return &GoFunctionCall{name: name, parameters: parameters}
}

func (a *GoFunctionCall) Dump(prefix string) {
//r := "resolved"
//if a.decl == nil {
// r = "not resolved"
//}
//fmt.Printf("%s FunctionCall %s %s\n", prefix, a.name, r)
for _, x := range a.parameters {
fmt.Printf("%s\tparameters: %#v\n", prefix, x)
}
}

func (a *GoFunctionCall) accept(visitor AstVisitor) interface{} {
return visitor.VisitGoFunctionCall(a)
}

type Variable struct {
Expression
name string
Expand Down
48 changes: 46 additions & 2 deletions duang/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (a Parser) parseVariableDecl() *VariableDecl {
var init *Expression
t1 := a.scanner.Peek()
// 类型标注
if t1.Text == ":" {
if t1.Text == "::" {
a.scanner.Next()
t1 = a.scanner.Peek()
if t1.Kind == KTokenKindIdentifier {
Expand Down Expand Up @@ -243,7 +243,9 @@ func (a Parser) parsePrimary() Expression {
//知识点:以Identifier开头,可能是函数调用,也可能是一个变量,所以要再多向后看一个Token,
//这相当于在局部使用了LL(2)算法。
if t.Kind == KTokenKindIdentifier {
if a.scanner.Peek2().Text == "(" {
if a.scanner.Peek2().Text == "::" {
return a.parseGoFunctionCall()
} else if a.scanner.Peek2().Text == "(" {
return a.parseFunctionCall()
} else {
a.scanner.Next()
Expand Down Expand Up @@ -320,6 +322,48 @@ func (a Parser) parseFunctionCall() *FunctionCall {
return nil
}

func (a Parser) parseGoFunctionCall() *GoFunctionCall {
params := make([]Expression, 0)
t := a.scanner.Next()
if t.Kind == KTokenKindIdentifier {
a.scanner.Next() // 跳过:
tRight := a.scanner.Next()
t1 := a.scanner.Next()
if t1.Text == "(" {
t1 = a.scanner.Peek()
//循环,读出所有参数
for t1.Text != ")" {
exp := a.parseExpression()
if exp != nil {
params = append(params, *exp)
} else {
fail("Error parsing parameter in function call")
return nil
}
t1 = a.scanner.Peek()
if t1.Text != ")" {
if t1.Text == "," {
t1 = a.scanner.Next()
} else {
fail("excepting a comma at the end of a function call, while we got a " + t1.Text)
return nil
}
}
}
//消化掉')'
a.scanner.Next()
t1 = a.scanner.Peek()
if t1.Text == ";" {
a.scanner.Next()
}
name := fmt.Sprintf("%s::%s", t.Text, tRight.Text)
n := NewGoFunctionCall(name, params)
return n
}
}
return nil
}

func (a Parser) parseImportDecl() *ImportStatement {
//跳过关键字'import'
a.scanner.Next()
Expand Down
6 changes: 5 additions & 1 deletion duang/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ func (a *Scanner) getToken() Token {
case "\"":
return a.parseStringLiteral()
case "(", ")", "{", "}", "[", "]", ",", ";", ":", "?", "@", "#":
a.charStream.Next()
ch2 := a.charStream.Next()
if ch == ":" && ch2 == ":" {
a.charStream.Next()
return Token{Kind: KTokenKindSeperator, Text: "::"}
}
return Token{Kind: KTokenKindSeperator, Text: ch}
case "/":
{
Expand Down
4 changes: 4 additions & 0 deletions duang/visitor_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ type AstVisitor interface {
VisitProg(prog *Prog) interface{}
VisitFunctionDecl(functionDecl *FunctionDecl) interface{}
VisitFunctionCall(functionCall *FunctionCall) interface{}
VisitGoFunctionCall(functionCall *GoFunctionCall) interface{}
VisitBlock(block *Block) interface{}
VisitVariableDecl(variableDecl *VariableDecl) interface{}
VisitBinary(exp *Binary) interface{}
Expand Down Expand Up @@ -95,3 +96,6 @@ func (a AstVisitorBase) VisitBooleanLiteral(exp *BooleanLiteral) interface{} {
func (a AstVisitorBase) VisitImport(imp *ImportStatement) interface{} {
return nil
}
func (a AstVisitorBase) VisitGoFunctionCall(imp *GoFunctionCall) interface{} {
return nil
}
35 changes: 19 additions & 16 deletions duang/visitor_semantic.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,28 +216,31 @@ func (a *Interpreter) VisitFunctionCall(functionCall *FunctionCall) interface{}
return strings.TrimRight(r, "\n")
}
default:
if strings.HasPrefix(functionCall.name, "go_") {
l := strings.SplitN(functionCall.name, "_", 3)
name := fmt.Sprintf("%s.%s", l[1], l[2])
v, err := interpreter.Eval(name)
if err != nil {
return err
}
f := v.Interface().(func(string) string)
retVal := a.Visit(functionCall.parameters[0])
o, ok := retVal.(*LeftValue)
if ok {
retVal = a.getVariableValue(o.variable.name)
}
msg := gconv.String(retVal)
return f(msg)
} else if functionCall.decl != nil {
if functionCall.decl != nil {
return a.VisitBlock(functionCall.decl.body)
}
}
return nil
}

func (a *Interpreter) VisitGoFunctionCall(goFunctionCall *GoFunctionCall) interface{} {
l := strings.SplitN(goFunctionCall.name, "::", 2)
name := fmt.Sprintf("%s.%s", l[0], l[1])
v, err := interpreter.Eval(name)
if err != nil {
return err
}
f := v.Interface().(func(string) string)
retVal := a.Visit(goFunctionCall.parameters[0])
o, ok := retVal.(*LeftValue)
if ok {
retVal = a.getVariableValue(o.variable.name)
}
msg := gconv.String(retVal)
return f(msg)

}

// VisitVariableDecl 变量声明,如果存在变量初始化部分,存下变量的值
func (a *Interpreter) VisitVariableDecl(variableDecl *VariableDecl) interface{} {
if variableDecl.init != nil {
Expand Down
4 changes: 2 additions & 2 deletions test_data/hello.duang
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn main(){
测试call()
print("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
print("调用go写的函数,虽然调用方式还不是很完美,函数签名受到限制但是终于能调用了!!!!!")
print(go_hello_hello("你好呀,go语言"))
print(hello::hello("你好呀,go语言"))
print("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
print(go_hello_word("你在干嘛呀"))
print(hello::channel("go chan支持测试"))
}
9 changes: 5 additions & 4 deletions test_data/src/github.com/gocode/hello/hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ func hello(msg string) string {
fmt.Printf("go 语言收到duang语言发的内容了:%s\n", msg)
return fmt.Sprintf("我是从go这边代码执行得到的结果,你收到了吗?")
}
func word(msg string) string {
fmt.Printf("go语言又收到了:%s\n", msg)
fmt.Println("go标准库的代码都能被解释执行,这边的输出会直接输出")
return "我是go语言函数提供的返回值"
func channel(msg string) string {
ch := make(chan string, 1)
ch <- msg
returnMsg := <-ch
return returnMsg
}

0 comments on commit f40676b

Please sign in to comment.