1 Star 1 Fork 1

U语言组织/U语言

forked from 秋来冬风/U语言 
加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
codeblock.go 12.29 KB
一键复制 编辑 原始数据 按行查看 历史
package check
import (
"gitee.com/u-language/u-language/ucom/ast"
"gitee.com/u-language/u-language/ucom/astdata"
"gitee.com/u-language/u-language/ucom/enum"
"gitee.com/u-language/u-language/ucom/errcode"
"gitee.com/u-language/u-language/ucom/internal/utils"
)
// checkCodeBlock 检查一个代码块
// - Left是代码块第一个节点在抽象语法树节点切片的偏移量
// - Right是代码块右大括号节点在抽象语法树节点切片的偏移量
// - sbt是代码块所属的符号表
// - tree是检查的抽象语法树,不能为nil
func checkCodeBlock(Left, Right int, sbt *ast.Sbt, table symbolCheckTable, ltabel labelTable, tree *ast.Tree, funcinfo *ast.FuncInfo, isinfor bool, goto_info []gotoStmtInfo, isswitchin bool, switch_expr_typ string, InAutoFree bool, IsGeneric bool, Nodes []ast.Node, off int) []codeBlockErr {
var ret = make([]codeBlockErr, 0)
var code errcode.ErrCode
var msg errcode.Msg
var left, right int
isfunc := false
foff := 0
ismethod := false
if Left != 0 {
_, ismethod = Nodes[Left-1].(*ast.MethodNode)
_, isfunc = Nodes[Left-1].(*ast.FuncNode)
foff = Left - 1
} else if Nodes[0] != nil {
_, ismethod = Nodes[0].(*ast.MethodNode)
_, isfunc = Nodes[0].(*ast.FuncNode)
}
if isfunc { //如果是函数代码块
info := sbt.Have(Nodes[foff].(*ast.FuncNode).Name)
funcinfo = info.PtrFuncInfo()
goto_info = make([]gotoStmtInfo, 0)
table.addParame(info.PtrFuncInfo().Parame, Left+1) //将函数参数视为局部变量
if len(funcinfo.TypeParame) != 0 { //如果是未实例化泛型,清除泛型节点
var left, right int
if IsGeneric {
left, right = Left+1, (Right - Left + 1)
} else {
left, right = Left, Right
}
clearGeneric(Nodes, left-1, right+1) //减1为了连声明一起清除,加1是为了连右大括号一起清除
return nil
}
}
if ismethod {
n := Nodes[foff].(*ast.MethodNode)
funcinfo = n.FuncInfo
table.addParame(funcinfo.Parame, Left+1)
if len(funcinfo.TypeParame) != 0 { //如果是未实例化泛型,清除泛型节点
var left, right int
if IsGeneric {
left, right = Left+1, (Right - Left + 1)
} else {
left, right = Left, Right
}
clearGeneric(Nodes, left-1, right+1) //减1为了连声明一起清除,加1是为了连右大括号一起清除
return nil
}
}
for i := Left; i < Right; i++ {
if utils.IsNil(Nodes[i]) {
continue
}
switch n := Nodes[i].(type) {
case *ast.VarNode: //是变量声明节点
table.Add(n.Name, i+1) //记录声明行数
code, msg = checkVar(n, sbt, tree, InAutoFree)
if code != errcode.NoErr { //如果使用在声明之前
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
case *ast.ConstNode: //是常量节点
table.Add(n.Name, i+1) //记录声明行数
code, msg = checkConst(n, sbt, tree, InAutoFree)
if code != errcode.NoErr { //如果使用在声明之前
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
if n.Value != nil {
code, msg := checkSrcUseSymbol(n.Value, table, sbt)
if code != errcode.NoErr { //如果使用在声明之前
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
}
case *ast.ASSIGNNode:
code, msg = CheckASSIGN(n, sbt, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
continue
}
code, msg, info, is_local_decl, _ := ret_info(n.Dest, sbt, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
continue
}
if is_local_decl { //目的操作数变量在当前作用域声明
code := table.Check(info.Name()) //检查使用是否在声明之前
if code != errcode.NoErr { //如果使用在声明之前
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: errcode.NewMsgSymbol(info.Name())})
}
}
code, msg = checkSrcUseSymbol(n.Src, table, sbt) //检查源操作数
if code != errcode.NoErr { //如果使用在声明之前
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
case *ast.IfNode: //是if节点
code, msg = CheckBoolExprNode(n.BoolExpr, n.Sbt, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
if IsGeneric {
left, right = i+1, (n.Right-n.Left+1)+i
} else {
left, right = n.Left, n.Right
}
ret = append(ret, checkCodeBlock(left, right, n.Sbt, table, ltabel, tree, funcinfo, isinfor, goto_info, isswitchin, switch_expr_typ, InAutoFree, IsGeneric, Nodes, off)...)
i = right
case *ast.ElseNode: //是else节点
code, msg = CheckBoolExprNode(n.BoolExpr, n.Sbt, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
if IsGeneric {
left, right = i+1, (n.Right-n.Left+1)+i
} else {
left, right = n.Left, n.Right
}
ret = append(ret, checkCodeBlock(left, right, n.Sbt, table, ltabel, tree, funcinfo, isinfor, goto_info, isswitchin, switch_expr_typ, InAutoFree, IsGeneric, Nodes, off)...)
i = right
case *ast.ForNode: //是for节点
if n.InitStmt != nil {
vn, ok := n.InitStmt.(*ast.VarNode)
if ok {
table.Add(vn.Name, i+1)
}
}
code, msg = checkFor(n, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
if IsGeneric {
left, right = i+1, (n.Right-n.Left+1)+i
} else {
left, right = n.Left, n.Right
}
ret = append(ret, checkCodeBlock(left, right, n.Sbt, table, ltabel, tree, funcinfo, true, goto_info, isswitchin, switch_expr_typ, InAutoFree, IsGeneric, Nodes, off)...)
i = right
case *ast.ReturnNode: //是返回语句
code, msg, typestr := ret_type_str(n.RetValue, sbt, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
continue
}
if len(funcinfo.RetValue) != 0 {
if !utils.Typ_is_equal(typestr, funcinfo.RetValue[0].Type.Typ()) { //如果声明的类型与返回的类型不相等
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: errcode.ReturnErr, Msg: errcode.NewMsgReturnTypeIsNotEqual(funcinfo.RetValue[0].Type.Typ(), typestr)})
continue
}
}
case *ast.LabelNode: //是标签
ltabel.Add(n.Value)
case ast.BreakStmt: //是berak语句
if !isinfor && !isswitchin { //如果同时不在for代码块和switch代码块中
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: errcode.BreakStmtInForOrSwitch, Msg: nil})
}
case ast.ContinueStmt: //是continue语句
if !isinfor { //如果不在for代码块中
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: errcode.ContinueStmtInFor, Msg: nil})
}
case *ast.SelfOpStmt: //是自操作语句
code, msg = checkSelfOpStmtCtx(n, sbt, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
case *ast.CallNode: //是调用节点
code, msg, _ = checkCall(n, sbt, tree, InAutoFree)
if code != errcode.NoErr {
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
case *ast.GotoStmt: //是goto语句
goto_info = append(goto_info, gotoStmtInfo{Ptr: n, LineNum: off + i + 1})
case *ast.FuncNode: //是函数声明
if IsGeneric {
left, right = i+1, (n.Right-n.Left+1)+i
} else {
left, right = n.Left, n.Right
}
ret = append(ret, checkCodeBlock(left, right, n.Sbt, table, ltabel, tree, funcinfo, isinfor, goto_info, isswitchin, switch_expr_typ, InAutoFree, IsGeneric, Nodes, off)...)
i = right
case *ast.SwitchNode: //是switch语句
code, msg := checkSrcUseSymbol(n.Expr, table, sbt)
if code != errcode.NoErr { //如果使用在声明之前
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
}
code, msg, switch_expr_typ = ret_type_str(n.Expr, n.Sbt, tree, InAutoFree)
if code != errcode.NoErr { //如果有错误
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
break
}
var left, right int
if IsGeneric {
left, right = i+1, (n.Right-n.Left+1)+i
} else {
left, right = n.Left, n.Right
}
ret = append(ret, checkCodeBlock(left, right, n.Sbt, table, ltabel, tree, funcinfo, isinfor, goto_info, true, switch_expr_typ, InAutoFree, IsGeneric, Nodes, off)...)
i = right
case *ast.CaseNode: //是case语句
if !isswitchin { //如果不在switch中
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: errcode.CaseStmtInSwitch, Msg: nil})
}
code, msg := checkSrcUseSymbol(n.Expr, table, sbt)
if code != errcode.NoErr { //如果使用在声明之前
ret = append(ret, codeBlockErr{Line: i + 1, Code: code, Msg: msg})
}
_, _, typ := ret_type_str(n.Expr, n.Sbt, tree, InAutoFree)
if typ != switch_expr_typ && switch_expr_typ != "" {
ret = append(ret, codeBlockErr{Line: i + 1, Code: errcode.TypeIsNotEqual, Msg: errcode.NewMsgSwitchAndCaseTypNoEqual(switch_expr_typ, typ)})
}
case *ast.MethodNode: //是方法声明
if IsGeneric {
left, right = i+1, (n.Right-n.Left+1)+i
} else {
left, right = n.Left, n.Right
}
ret = append(ret, checkCodeBlock(left, right, n.Sbt, table, ltabel, tree, funcinfo, isinfor, goto_info, isswitchin, switch_expr_typ, true, IsGeneric, Nodes, off)...)
i = right
case *ast.AutoFreeNode: //是自动释放块
code, msg, expr_typ := ret_type_str(n.Expr, n.Sbt, tree, InAutoFree)
if code != errcode.NoErr { //如果有错误
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: code, Msg: msg})
break
}
if expr_typ != enum.Int { //如果表达式不表示整数
ret = append(ret, codeBlockErr{Line: off + i + 1, Code: errcode.ExprForAutoFreeShouldExprInt, Msg: nil})
break
}
var left, right int
if IsGeneric {
left, right = i+1, (n.Right-n.Left+1)+i
} else {
left, right = n.Left, n.Right
}
ret = append(ret, checkCodeBlock(left, right, n.Sbt, table, ltabel, tree, funcinfo, isinfor, goto_info, isswitchin, switch_expr_typ, true, IsGeneric, Nodes, off)...)
i = right
}
}
if isfunc || ismethod { //如果是函数,检查goto语句
ret = append(ret, checkAllgoto(goto_info, ltabel)...)
}
return ret
}
func clearGeneric(nodes []ast.Node, Left int, Right int) {
for i := Left; i < Right; i++ {
nodes[i] = nil
}
}
// checkSrcUseSymbol 检查节点中的变量,使用是否在声明之前
func checkSrcUseSymbol(src ast.Node, table symbolCheckTable, sbt *ast.Sbt) (errcode.ErrCode, errcode.Msg) {
switch src := src.(type) {
case *ast.Object: //是对象节点
if src.Kind == ast.SymbolObj {
if _, ok := sbt.Have2(src.Name); ok { //使用的变量是在当前作用域声明
if code := table.Check(src.Name); code != errcode.NoErr { //如果变量使用在声明之前
return code, errcode.NewMsgSymbol(src.Name)
}
}
}
case *ast.OpExpr: //是运算表达式节点
code, msg := checkSrcUseSymbol(src.Src1, table, sbt) //检查源操作数1
if code != errcode.NoErr { //发现错误
return code, msg
}
code, msg = checkSrcUseSymbol(src.Src2, table, sbt) //检查源操作数2
if code != errcode.NoErr { //发现错误
return code, msg
}
}
return errcode.NoErr, nil
}
type symbolCheckTable map[string]int //key=符号名 value=是声明的行数
// Add 记录变量声明的行数,ast保证同一作用域不会有重名变量
func (t symbolCheckTable) Add(name string, line int) {
t[name] = line
}
// Check 检查使用是否在声明之前
func (t symbolCheckTable) Check(name string) errcode.ErrCode {
_, ok := t[name]
if !ok {
return errcode.SymbolUseBeforeDeclaration
}
return errcode.NoErr
}
// addParame 添加参数为已声明的局部变量
func (t symbolCheckTable) addParame(parame []astdata.Parame, line int) {
for _, v := range parame {
t.Add(v.Name, line)
}
}
type codeBlockErr struct {
Msg errcode.Msg
Line int
Code errcode.ErrCode
}
// labelTable 标签表
type labelTable map[string]struct{}
// Add 记录变量声明的行数,ast保证同一作用域不会有重名变量
func (t labelTable) Add(name string) {
t[name] = struct{}{}
}
// Have 检查使用是否在声明之前
func (t labelTable) Have(name string) bool {
_, ok := t[name]
return ok
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/u-language/u-language.git
git@gitee.com:u-language/u-language.git
u-language
u-language
U语言
df767d8a61bb

搜索帮助