Skip to content

Commit

Permalink
去除 metatable 属性,直接将其置于 luaTable 对象中
Browse files Browse the repository at this point in the history
  • Loading branch information
lollipopkit committed Oct 3, 2022
1 parent 54f142a commit abcf643
Show file tree
Hide file tree
Showing 15 changed files with 108 additions and 177 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- 支持面向对象
- `REPL`支持自动添加`print`
- 不再支持任意对象 `concat`,如不能拼接则会返回 `""`
- 去除 `metatable` 属性,直接将其置于 `luaTable` 对象中

## 0.1.2
- `Table`索引从`0`开始
Expand Down
78 changes: 36 additions & 42 deletions LANG.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,32 +284,53 @@ shy add = fn (a, b) {
除去常规的函数声明,`LK` 还可以将函数赋值给变量,这样可以实现匿名函数。


## 元表
## 面向对象 & 元表
```js
class mt {}
// 定义一个类,包含其默认属性值(x = 0, y = 0)
class Vector { 'x': 0, 'y': 0 }

// 创建一个 Vector 对象,调用这个方法可以在初始化对象时,为内部属性赋值
// 如果使用`new(Vector)`,则会使用默认值(x = 0, y = 0)
fn Vector.new(x, y) {
shy v = new(Vector)
v.x = x
v.y = y
rt v
}

mt.__add = fn(v1, v2) {
rt vector(v1.x + v2.x, v1.y + v2.y)
fn Vector.__add(v1, v2) {
v = new(Vector)
v.x = v1.x + v2.x
v.y = v1.y + v2.y
rt v
}
mt.__str = fn(v) {
rt 'vector(' + v.x + ', ' + v.y + ')'

fn Vector:set(x, y) {
self.x = x
self.y = y
}

shy fn vector(x, y) {
shy v = {'x': x, 'y': y}
setmetatable(v, mt)
rt v
fn Vector:__str() {
rt 'Vector(' + str(self.x) + ', ' + str(self.y) + ')'
}

shy v1 = vector(1, 2)
shy v2 = vector(3, 5)
// 使用的`mew(Object)`,所以使用的默认属性值
// 此时 x = 0, y = 0
shy v1 = new(Vector)
// 带值的初始化对象
// 此时x = 3, y = 4
shy v2 = Vector.new(3, 4)
// 调用Vector:set(x, y)方法,修改v1的值
v1:set(1, 2)
shy v3 = v1 + v2
print(v3.x, v3.y)
print(fmt('%s + %s = %s', v1, v2, v3))
print(v3.x, v3.y) // 4 6
print(fmt('%s + %s = %s', v1, v2, v3)) // Vector(1, 2) + Vector(3, 4) = Vector(4, 6)
```
`print` 时,如果是非 `str` 类型,会调用 `__str` 方法。
`vector` 没有内置的 `+` 方法,所以会调用 `mt``__add` 方法。
以下是可以拓展的元方法表:

以下是可以拓展的元方法表:

|操作符/作用|metatable|
|-|-|
|`+`|`__add`|
Expand All @@ -332,33 +353,6 @@ print(fmt('%s + %s = %s', v1, v2, v3))
|调用方法|`__call`|
|获取名称|`__name`|
|迭代器|`__range`|
|元表|`__metatable`|


## 面向对象
```js
// 定义一个class Rect,为其内部属性赋值初始值
class Rect {
'width': 0,
'height': 0
}

// 给class Rect添加一个函数,可以用来打印Rect的信息
fn Rect:printArea() {
print("Rect area: ", self.width * self.height)
}

fn Rect:set(width, height) {
self.width = width
self.height = height
}

shy rect = new(Rect)
// 因为还没有赋值宽高,所以面积为0
rect:printArea() // Rect area: 0
rect:set(10, 20)
rect:printArea() // Rect area: 200
```


##
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

<p align="center">
<img alt="badge-lang" src="https://badgen.net/badge/Lang/LK/cyan">
<img alt="badge-lang" src="https://badgen.net/badge/Lk/0.1.1/blue">
<img alt="badge-lang" src="https://badgen.net/badge/Go/1.19/purple">
</p>

Expand Down Expand Up @@ -55,7 +54,8 @@ fn Header:fromTable(h) {
rt self
}

fn Header:toString() {
// 对象在被`print`时,如果非`string`类型,会调用`__str`方法
fn Header:__str() {
shy s = ''
for k, v in self.items {
s = fmt('%s%s: %s\n', s, k, v)
Expand All @@ -69,7 +69,7 @@ fn Header:toString() {
*/
shy fn handle(req) {
shy h = Header:fromTable(req.headers)
rt 200, fmt('%s %s\n\n%s\n%s', req.method, req.url, h:toString(), req.body)
rt 200, fmt('%s %s\n\n%s\n%s', req.method, req.url, h, req.body)
}

// 监听
Expand All @@ -85,7 +85,7 @@ if http.listen(':8080', handle) != nil {
- [x] Raw String, 使用 ``` ` ``` 包裹字符
- [x] 支持任意对象拼接( `concat` ),使用语法 `..`
- [x] 面向对象
- [ ] Table
- [x] Table
- [x] key为StringExp,而不是NameExp
- [x] 构造方式:`=` -> `:`, eg: `{a = 'a'}` -> `{a: 'a'}`
- [x] 索引从 `0` 开始
Expand Down
2 changes: 0 additions & 2 deletions api/lua_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,13 @@ type BasicAPI interface {
GetI(idx int, i int64) LuaType
RawGet(idx int) LuaType
RawGetI(idx int, i int64) LuaType
GetMetatable(idx int) bool
GetGlobal(name string) LuaType
/* set functions (stack -> Lua) */
SetTable(idx int)
SetField(idx int, k string)
SetI(idx int, i int64)
RawSet(idx int)
RawSetI(idx int, i int64)
SetMetatable(idx int)
SetGlobal(name string)
Register(name string, f GoFunction)
/* 'load' and 'call' functions (load and run Lua code) */
Expand Down
11 changes: 8 additions & 3 deletions repl.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"fmt"
"os"
"regexp"
"strings"
Expand All @@ -26,6 +25,7 @@ var (
consts.ClassDefReStr,
}, "|"))
promptLen = len([]rune(prompt))
printReg = regexp.MustCompile(`print\(.*\)`)
)

const (
Expand Down Expand Up @@ -79,7 +79,6 @@ func repl() {

func catchErr(ls *api.LkState, first *bool, cmd string) {
if err := recover(); err != nil && *first {
cmd = fmt.Sprintf("print(%s)", cmd)
*first = false
(*ls).LoadString(cmd, "stdin")
}
Expand All @@ -89,7 +88,13 @@ func protectedLoadString(ls *api.LkState, cmd string) {
first := true
// 捕获错误
defer catchErr(ls, &first, cmd)
(*ls).LoadString(cmd, "stdin")
addedPrintCmd := func() string {
if printReg.MatchString(cmd) {
return cmd
}
return "print(" + cmd + ")"
}()
(*ls).LoadString(addedPrintCmd, "stdin")
}

func updateHistory(str string) {
Expand Down
64 changes: 32 additions & 32 deletions state/api_arith.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,38 +55,38 @@ var operators = []operator{
{"__bnot", bnot, nil},
}

func ArithName(a ArithOp) string {
switch a {
case LUA_OPADD:
return "add"
case LUA_OPSUB:
return "sub"
case LUA_OPMUL:
return "mul"
case LUA_OPMOD:
return "mod"
case LUA_OPPOW:
return "pow"
case LUA_OPDIV:
return "div"
case LUA_OPIDIV:
return "idiv"
case LUA_OPBAND:
return "band"
case LUA_OPBOR:
return "bor"
case LUA_OPBXOR:
return "bxor"
case LUA_OPSHL:
return "shl"
case LUA_OPSHR:
return "shr"
case LUA_OPUNM:
return "unm"
case LUA_OPBNOT:
return "bnot"
func opSymbol(opName string) string {
switch opName {
case "__add":
return "+"
case "__sub":
return "-"
case "__mul":
return "*"
case "__mod":
return "%"
case "__pow":
return "^"
case "__div":
return "/"
case "__idiv":
return "~/"
case "__band":
return "and"
case "__bor":
return "or"
case "__bxor":
return "xor"
case "__shl":
return "<<"
case "__shr":
return ">>"
case "__unm":
return "-"
case "__bnot":
return "not"
default:
panic("invalid arith op: "+fmt.Sprint(a))
return opName
}
}

Expand Down Expand Up @@ -127,7 +127,7 @@ func (self *luaState) Arith(op ArithOp) {

self.stack.push(a)
self.stack.push(b)
panic(fmt.Sprintf("invalid arith: %v <%v> %v", self.TypeName(-3), ArithName(op), self.TypeName(-2)))
panic(fmt.Sprintf("invalid arith: %T<%#v> %s %T<%#v>", a, a, opSymbol(mm), b, b))
}

func _arith(a, b any, op operator) any {
Expand Down
15 changes: 0 additions & 15 deletions state/api_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,6 @@ func (self *luaState) Register(name string, f GoFunction) {
self.SetGlobal(name)
}

// [-1, +0, –]
// http://www.lua.org/manual/5.3/manual.html#lua_setmetatable
func (self *luaState) SetMetatable(idx int) {
val := self.stack.get(idx)
mtVal := self.stack.pop()

if mtVal == nil {
setMetatable(val, nil, self)
} else if mt, ok := mtVal.(*luaTable); ok {
setMetatable(val, mt, self)
} else {
panic("table expected, got " + fmt.Sprintf("%v", mtVal))
}
}

// t[k]=v
func (self *luaState) setTable(t, k, v any, raw bool) {
if tbl, ok := t.(*luaTable); ok {
Expand Down
4 changes: 1 addition & 3 deletions state/lua_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

type luaTable struct {
metatable *luaTable
arr []any
_map map[any]any
keys map[any]any // used by next()
Expand Down Expand Up @@ -36,8 +35,7 @@ func newLuaTable(nArr, nRec int) *luaTable {
}

func (self *luaTable) hasMetafield(fieldName string) bool {
return self.metatable != nil &&
self.metatable.get(fieldName) != nil
return self.get(fieldName) != nil
}

func (self *luaTable) len() int {
Expand Down
11 changes: 1 addition & 10 deletions state/lua_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func _stringToInteger(s string) (int64, bool) {

func getMetatable(val any, ls *luaState) *luaTable {
if t, ok := val.(*luaTable); ok {
return t.metatable
return t
}
key := fmt.Sprintf("_MT%d", typeOf(val))
if mt := ls.registry.get(key); mt != nil {
Expand All @@ -90,15 +90,6 @@ func getMetatable(val any, ls *luaState) *luaTable {
return nil
}

func setMetatable(val any, mt *luaTable, ls *luaState) {
if t, ok := val.(*luaTable); ok {
t.metatable = mt
return
}
key := fmt.Sprintf("_MT%d", typeOf(val))
ls.registry.put(key, mt)
}

func getMetafield(val any, fieldName string, ls *luaState) any {
if mt := getMetatable(val, ls); mt != nil {
return mt.get(fieldName)
Expand Down
Loading

0 comments on commit abcf643

Please sign in to comment.