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

最新动态 #1

Closed
duangsuse opened this issue May 6, 2018 · 15 comments
Closed

最新动态 #1

duangsuse opened this issue May 6, 2018 · 15 comments
Assignees
Labels
enhancement New feature or request semantic Lite semantic syntax Lite syntax WIP Work In Progress

Comments

@duangsuse
Copy link
Collaborator

最终还是决定暂时重写了(简单重写)
去除重复无用代码和支持更多语法以及小特性
不去除 end

决定是使用 JFlex + PEG.js 解决解析问题, Java 能复用的代码依然复用
为了体积(和我对其它 JVM 语言不熟悉,而且大都比较复杂)依然使用 Java 编写

@duangsuse duangsuse self-assigned this May 6, 2018
@duangsuse
Copy link
Collaborator Author

另外我认为可以使用松的解析器方案:

使用 PEG.js 作为解析器生成器, 目标是生成序列化 JSON,需要使用的时候让解释器反序列化得到 AST

完美解决了解析问题

@duangsuse
Copy link
Collaborator Author

上面的: PEG.js 其实不需要额外的 scanner, 所以就不要 JFlex 了

@duangsuse
Copy link
Collaborator Author

duangsuse commented May 6, 2018

duangsuse 来制定一下重写添加的特性:

lay << @text # 这是 Lite 1.1 的语法, AST 解释器的内部隐式方法调用支持内部实现 def LinearLayout$add .....

  • 内部特殊方法调用支持 Lite fallback

for i in 1..4

  • 支持基于 range 的 for (和 range)

case input.text
"OC<"
puts ""
contains "foo" exit
nil exit if false
length(0) puts "${input.text}"

  • 支持 case 语句

  • 支持 "$variable" "${expression}" 字符串内联表达式

puts "Hello" "Word\n"

  • 高级的块参数填充(*varargs/name=default)

  • 参考 BeanShell 为解释器实现 Java 接口 (java.io.Serializable, 从 Object 类实现)

  • 参考 BeanShell 默认加载一些 Java 包

  • 使用松耦合解析器(Reflect 调用解析器),允许将 Lite 代码文本「编译」成 AST JSON, 执行时加载

^ 吐:这怎么能算编译呢,(迫真)编译 和之前 MonkeyVM 的 「编译」 一个意思,换汤不换药

  • 分别为 Android 和 JavaSE 平台实现 PEG.js 解析器接口

trace 1

  • 删除不必要的语法

if true
end

  • 使用 end 语义替换缩进语义

  • 内建 AST Formatter 支持缩进格式化

  • 提高内部代码重用数量

  • 写好 JavaDoc

  • 为实现过程写尽可能多的注释

  • 完全测试(但不测试驱动开发)

  • 包装好,使用 CI(后事)

  • 为代码文本处理部分添加 DeflatorJsonAst

def Object.eq?

  • Fallback 方法允许向类继承树上查找到 java.lang.Object

def System.out.cprintln

  • 基于对象 hash 的 singleton Fallback 方法

when a
is 1 or 2 or 3

  • 支持 or/and 操作符

  • 二元操作中支持数值类型自动提升 (参考 BeanShell)

  • 支持 paren expression

下一次

为 Lite 设计一个虚拟机,并添加编译器,允许在一个 Interpreter 上下文中同时使用 AST 解释器和字节码解释器

下下一次

做一个 Lite2Java 编译器, 或许不能实现什么动态特性但可以看作 Java 语法糖 进一步精简体积的方法和提升性能的方法

@duangsuse
Copy link
Collaborator Author

duangsuse commented May 6, 2018

(综上我总觉得不支持基于缩进的语义是一场遗憾....)
下一个手写解析器版本我一定会支持缩进语义(如果大部分人支持)

对比(这里是直接在 Ruby 上修改作为参考):

# The Greeter class
class Greeter
  def initialize(name)
    @name = name.capitalize
  def salute
    puts "Hello #{@name}!"

# Create a new object
g = Greeter.new("world")

# Output "Hello World!"
g.salute
# The Greeter class
class Greeter
  def initialize(name)
    @name = name.capitalize
  end

  def salute
    puts "Hello #{@name}!"
  end
end

# Create a new object
g = Greeter.new("world")

# Output "Hello World!"
g.salute

@duangsuse
Copy link
Collaborator Author

duangsuse commented May 6, 2018

 * Complete Lite Syntax (DNF 范式, 是 duangsuse 设计的一种即使没有规则你们也能看懂的无上下文词条流模式文法描述)
 * (看起来很高大上的东西, 其实没啥用.....)
 * Lite 的一个比较特殊的地方在于使用缩进语义, 我也是为了好看... 不过如果使用递归下降法, 解析不是问题耶
 * 强制你使用 duangsuse 喜欢的 2 空格缩进代码风格, 语言本身类似 Ruby (Ruby 岛国语言好耶)
 * 有趣的语法: ![str1 str2 str3] . each { |e| puts e } if a == 1 & b === :c
 *
 * #### TABLED symbol ####
 * newline  : '\n'
 * ident    : '  '
 * l_square : '['
 * r_square : ']'
 * let      : '='
 * at       : '@'
 * call     : '()'
 * bang     : '!'
 * sub      : '-'
 * inc      : '++'
 * dec      : '--'
 * #### FINISH symbol ####
 *
 * math -> expr Maybe( '+' OR '-' OR '*' OR '/' OR '**' OR '%' OR '<' OR '<=' OR '>' OR '>=' OR '&' OR '|' OR '==' OR '===' OR '!=' OR '<<' ) expr
 * binary -> math | cast | dot | in | square | stabby
 * expression -> binary | list | table | value | incDec | not | negative | call | identifier | index | blockProcedure | doBlock
 * statement -> def | for | scope | while | if | excited_statement
 * excited_statement -> break | next | import | require | return | trace | assignment | indexLet | square | stabby | dot | incDec | call Maybe( IF expression )
 * block -> Ary( IDENT statement NEWLINE )
 * for -> FOR identifier IN expression NEWLINE block
 * while -> WHILE expression NEWLINE block
 * scope -> SCOPE NEWLINE block
 * indexLet -> expression L_SQUARE expression R_SQUARE LET expression
 * index -> expression L_SQUARE expression R_SQUARE
 * if -> IF expression NEWLINE block Maybe( Ary( IDENT ELIF expression NEWLINE block ) ) Maybe( IDENT ELSE NEWLINE block )
 * identifier -> Maybe( AT ) label
 * def -> DEF identifier Maybe( nameList ) NEWLINE block
 * call -> identifier Maybe( CALL OR exprList )
 * assignment -> identifier LET expression
 * not -> BANG expression
 * negative -> SUB expression
 * incDec -> identifier Maybe( INC OR DEC )
 * trace -> TRACE Maybe( Ary( Any() ) )
 * return -> RETURN expression
 * require -> REQUIRE Any()
 * next -> NEXT
 * break -> BREAK
 * import -> IMPORT Maybe( Ary( Any() ) )
 * value -> TRUE | FALSE | NIL | Number() | string
 * string -> '"' Maybe( Ary( Any() ) ) '"' | stringB | stringC
 * stringB -> "'" Maybe( Ary( Any() ) ) "'"
 * stringC -> ':' label
 * list -> Maybe( BANG ) L_SQUARE exprList R_SQUARE
 * table -> '{' kvList '}'
 * kvList -> Ary( label ':' expression Maybe( ',' OR NEWLINE ) )
 * stabby -> expression '->' label expression
 * square -> expression '::' label
 * in -> expression IN expression
 * dot -> expression '.' label Maybe( CALL OR exprList )
 * cast -> expression AS label
 * exprList -> Ary( expr Maybe( ' ' OR ',' ) )
 * nameList -> Maybe( '(' ) Ary( name Maybe( ',' OR ' ' ) ) Maybe( ')' )
 * nameListB -> '|' Ary( name Maybe( ',' OR ' ' ) ) '|'
 * blockProcedure -> '{' Maybe( nameListB ) Ary( excited_statement ':' ) '}'
 * doBlock -> DO Maybe ( nameListB ) block

这些是现在 Lite 的语法,准备根据新特性修改一下,然后创建一个 JSON AST 描述,就可以开始补齐 PEG 需要的信息,然后就可以开始制定 PEG.js 语法规则了,在那之前我得看看 MIT 许可的 javascript parser example, 从中有不少可以用的代码片段

这个版本的语法使用 end 标识块结束,所以比之前用缩进的更「普通」一些,使用 parserc 很好解决

^ 上面的,其实也可以把使用缩进的语法转换为使用 end 的语法,这个版本的 Lite 就这么做过,不过由于 duangsuse IQ 不够高 开始没分析好导致太多次失败,duangsuse 已经失去了信心

@duangsuse
Copy link
Collaborator Author

duangsuse commented May 6, 2018

关于 case 语句:

case "foo bar"
  when contains "foo" { }
  when equals nil
    puts :nil
  end
  when "bar foo" { exit() }
  when toString "emm" {}
end

case Token(0, TokenType::EOF, '')
  when isNewline {}
  when is TokenType::REQUIRE
    return
  end
  when nil {}
end

具体来说是 when 后的词条若是 identifier (+ expression) (直到 {), 就是特殊的 when
特殊的 when 这样判断:
尝试 object 的 identifier 方法, 如果是无参方法, 调用结果与后面的 expression 结果比对

如果有且只有一个参数参数并且返回值是 Boolean/boolean, 意为使用后面的 expression 值调用方法, 作为结果

否则就是 identifier 表达式(如果有 expression, 无法识别即抛出异常)

case a
when in "" {}
end

我还是觉得这样优雅一些

foo = String()
foo = 1 if Math.random > 0.5

when foo
  class String # getClass() == String
    puts foo
  class Double
    puts "${foo}D"
  is 1
    exit()
  is 0 or 2 or 3
    puts()

Math.random

  • 这个语法是通过 def Math.getRandom 实现的(Lite method fallback 和对 fallback 的内部支持)

@duangsuse
Copy link
Collaborator Author

上面的表述还不够清晰, 以后会对整体语义在 wiki 里给出严谨简明的解释

@duangsuse duangsuse added enhancement New feature or request WIP Work In Progress syntax Lite syntax semantic Lite semantic labels May 6, 2018
@duangsuse
Copy link
Collaborator Author

duangsuse commented May 7, 2018

刚才是想依然手写 parser... 算了
所以啊我为了方便某些特殊语法会保留 Lexer

puts "$a ."
if a === 1
puts a

(Lite 的部分特殊语法需要特殊变换,比如给缩进语义加 end, "l${expression}r" 脱糖 "l" + expression + "r") (还是打算使用缩进语义, 不然不好看)

之前打算放在 parser 包里的类可以直接放在 root 下面 (添加 end 的 Deflator, 和序列化/反序列化 AST 的 JsonAst)

@duangsuse
Copy link
Collaborator Author

https://github.com/harc/ohm

作为生成器也是可以的,它比 Jison 和 PEG.js 都更加积极的在维护,而且工具很齐全

@duangsuse
Copy link
Collaborator Author

duangsuse commented May 7, 2018

关于 def 语法的问题

def 的特殊标识符(就是使用 '.' 语法的标识符)(对于一个 identifier 来说没有什么特殊的,但 Lite 目前不能解析带 '.' 的 identifier(和那个 '.' 操作符冲突了)
Lite def 目前可以使用带 '.' 的特殊 全局 标识符语法来创建特殊的方法(在 Lite 内部表示为 全局上下文 的普通变量 java_lang_System!println xor@java_lang_Number $ xor Missing_java_lang_Object (Lite 那时不支持内部类, 这次应该会支持, 内部类的 $ 会被看作 .))

  • def 到 Map<String, ?> (同时也是 Lite 的 Table) 中
a = { self: nil }
def a.new(obj)
  a->self { obj: obj }
  a->print { print self.obj }
aa = a.new 1 + 1
aa.print()
# 如果是 @a 就直接用
# @a->new do |obj| 吧

Java FFI 的用途

  • 为类创建静态方法 fallback java_lang_System!getEnv
  • 为类创建方法 fallback join@java_lang_String
  • 为类创建 methodMissing Missing!java_lang_Object
  • 为对象创建单例方法 Singleton_(hashcode)

关于 named scope 支持

突然脑洞想到可以有一种新的模块化设计支持

# file a
import android.widget

scope android
  def @LinearLayout.add(v)
    self.addView(v)

# file b
scope android
  lay << Button(ctx)

... 不知道有没有价值,不过我看可能对模块化设计比较有用,不如加上试试

@duangsuse
Copy link
Collaborator Author

duangsuse commented May 7, 2018

既然新特性都设定好了,接下来开始定义词法和语法等:
制定完成后会同步到 wiki 里

Lite 词法

Lite 语法语义

Lite 最有用的 Java API

Interpreter

Lexer

Deflator

AstJson

Block

@duangsuse
Copy link
Collaborator Author

duangsuse commented May 7, 2018

追加一个语法特性:

String 字面量支持更多 escape

参考 https://github.com/lice-lang/lice/blob/master/src/main/kotlin/org/lice/parse/Lexer.kt#L189

参考 http://ice1000.org/2018/02/18/SyntaxDesign/ 里的尴尬情况,
当然 Lite 的词法很简单,不存在此问题(String 字面就是 String 字面,当前版本也没有太多转义 而且转义是后来处理的,字符串在解析过程中也没有什么特殊处理,就是 '"' string data '"')

如果转义不对,Lite 的 Lexer 要失败报错(同时现在 Lexer 的错误检查也太弱了,得增强一下)

对于 0x 0b 0o 这种数字字面量变换语法,也要支持(不是在分词器里,因为那里只认为数字是 [0-9] 到 一个空白字符结束)

但 012345 这种令人费解的 8 进制语法不可以支持,不得不说这么设计的确很纸张....

^ 以上,我突然觉得这很没意思,我想支持这种语法的目的是需要这类字面量的(比如处理二进制)的脚本可以更方便的让解析器帮你换算进位,但是后来又发现其实这库函数也可能帮你做

于是我决定不支持这类特殊的 numeric literal, 抱歉
现在 Lite 的 numeric literal 其实已经够用了,Lite 的设计就是简单,越简单越好,只应该保留最常用的功能

另外还有一个:duangsuse 现在还难以理解大部分正则表达式(其实是不想看,不过以后...算了)
(一些大佬又要喷我菜了....)所以支持这类特殊的 numeric 表达方式会累死 duangsuse, 当然不可以支持

如果可能的话,Lexer 和 Parser 这种机械化的东西我会使用 JFlex/PEG.js|OHM.js 自动生成

@duangsuse
Copy link
Collaborator Author

NOTE: 解析方案依然是那个解析方案, 不过改用修改 JavaScript.pegjs

@duangsuse
Copy link
Collaborator Author

最后的 parsing 商议结果:

基于 JavaScript 定义两套词法,一套支持语法糖一套不支持
手写支持语法糖和缩进的 lexer,另外一套给 PEG parserc 用

定义两套语法,一套使用 end 一套使用缩进
使用第一套 sugared 语法的由内建的 Lexer 和 Flatter 分词脱糖,转换成另外一种可以简单解析的语法

然后交给可能的 PEG.js 生成的解析器使用,这个解析器在 JavaScript parser 基础上修修补补实现

@duangsuse
Copy link
Collaborator Author

最最后的:

还是先不过分美化语法吧,以后彻底手写了再作打算

Mikecovlee 于 知乎提问 https://www.zhihu.com/question/40786019 上写道:

1. CovScript编程语言的前身CovBasic编程语言初期版本是纯解释型编程语言,解释器能力孱弱,选择end有利于简化解释器。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request semantic Lite semantic syntax Lite syntax WIP Work In Progress
Projects
None yet
Development

No branches or pull requests

1 participant