Skip to content

Instantly share code, notes, and snippets.

@hsk
Last active June 24, 2016 05:30
Show Gist options
  • Save hsk/04d0e9aa259f8f7a0b832c4dfe8c53b0 to your computer and use it in GitHub Desktop.
Save hsk/04d0e9aa259f8f7a0b832c4dfe8c53b0 to your computer and use it in GitHub Desktop.
# Klassic言語仕様
## Klassicの開発ポリシー
基本的にScalaを改良しつつ、最初はコアな機能を作成し、パーシャルファンクション等の細かい機能は後からつける。
EOF ::= not(elem(".", (ch: Char) => ch != CharSequenceReader.EofCh), "EOF Expected")
LINEFEED ::= ("\r\n" | "\r" | "\n")
SEMICOLON ::= ";"
ANY ::= elem(".", (ch: Char) => ch != CharSequenceReader.EofCh)
SPACING ::= (COMMENT | "\r\n" | "\r" | "\n" | " " | "\t" | "\b" | "\f")*
SPACING_WITHOUT_LF ::= (COMMENT | "\t" | " " | "\b" | "\f")*
TERMINATOR ::= (LINEFEED | SEMICOLON | EOF) SPACING
SEPARATOR ::= (LINEFEED | COMMA | EOF | SPACING_WITHOUT_LF) SPACING
## コメント
BLOCK_COMMENT ::= "/*" (not("*/") (BLOCK_COMMENT | ANY))* "*/"
LINE_COMMENT ::= "//" (not(LINEFEED) ANY)* LINEFEED
COMMENT ::= BLOCK_COMMENT | LINE_COMMENT
コメントは、ブロックコメントと一行コメントがあります。ブロックコメントはネストすることが可能です。
## 演算子
LT ::= "<"
GT ::= ">"
LTE ::= "<="
GTE ::= ">="
PLUS ::= "+"
MINUS ::= "-"
ASTER ::= "*"
SLASH ::= "/"
## 括弧
LPAREN ::= "("
RPAREN ::= ")"
LBRACE ::= "{"
RBRACE ::= "}"
LBRACKET ::= "["
RBRACKET ::= "]"
COMMA ::= ","
DOT ::= "."
EQ ::= "="
EQEQ ::= "=="
ARROW ::= "=>"
COLON ::= ":"
QUES ::= "?"
AMP2 ::= "&&"
BAR2 ::= "||"
## キーワード
IF ::= "if"
ELSE ::= "else"
WHILE ::= "while"
FOREACH ::= "foreach"
IMPORT ::= "import"
TRUE ::= "true"
FALSE ::= "false"
IN ::= "in"
CLASS ::= "class"
DEF ::= "def"
VAL ::= "val"
NEW ::= "new"
# 型
typeAnnotation ::= ":" ("Byte" | "Short" | "Int" | "Long" | "Float" | "Double" | "Boolean" | "Unit" | "?" | "*")
現状はユーザー定義型はなくて考え中
Scalaのsealed class,trait case classをもっと短く書けるようにする
program ::= SPACING repsep(import TERMINATOR) (lines opt(TERMINATOR))
import ::= IMPORT fqcn
lines ::= SPACING repsep(line, TERMINATOR) opt(TERMINATOR)
line ::= expression | val_declaration | functionDefinition
expression ::= assignment | logical | ifExpression | whileExpression | foreachExpression
//if ::= "if" "(" expression ")" expression "else" expression
ifExpression ::= IF LPAREN expression RPAREN expression ELSE expression
//while ::= "while" "(" expression ")" expression
whileExpression ::= WHILE LPAREN expression RPAREN expression
//foreach ::= "foreach" "(" ident "in" expression ")" expression
foreachExpression ::= FOREACH LPAREN ident IN expression RPAREN expression
logical ::= chainl1(conditional, AMP2 | BAR2)
//conditional ::= add {"<" add | ">" add | "<=" add | ">=" add}
conditional ::= chainl1(add, EQEQ | LTE | GTE | LT | GT)
//add ::= term {"+" term | "-" term}
add ::= chainl1(term, PLUS | MINUS))
//term ::= factor {"*" factor | "/" factor}
term ::= chainl1(unary, ASTER | SLASH)
unary ::= (MINUS unary | PLUS unary | invocation)
invocation ::= application DOT ident opt(LPAREN repsep(expression, COMMA) RPAREN)*
application ::= primary opt(LPAREN repsep(expression, COMMA) SPACING RPAREN)
//primary ::= intLiteral | stringLiteral | listLiteral | "(" expression ")" | "{" lines "}"
primary ::= ident | floatLiteral | integerLiteral | stringLiteral | listLiteral | newObject | anonymousFunction | LPAREN expression RPAREN | LBRACE lines RBRACE | hereDocument
## 整数
//intLiteral ::= ["1"-"9"] {"0"-"9"}
integerLiteral ::= ("""[1-9][0-9]*|0""" opt("BY"| "L" | "S")
## 浮動小数点数
floatLiteral ::= ("([1-9][0-9]*|0)\\.[0-9]*".r opt("F"))
## ブーリアン
booleanLiteral ::= (TRUE | FALSE)
## 文字列
//stringLiteral ::= "\"" ((?!")(\[rntfb"'\\]|[^\\]))* "\""
stringLiteral ::=
("\"" ~>
(% ~ """((?!("|#\{))(\\[rntfb"'\\]|[^\\]))+""".r ^^ {case location ~ in =>
StringNode(location, unescape(in))
} | "#{" ~> expression <~ "}"
).*
<~ "\"" ^^ { values =>
values.foldLeft(StringNode(NoLocation, ""):AstNode) { (node, content) => BinaryExpression(content.location, Operator.ADD, node, content) }
}) <~ SPACING_WITHOUT_LF
listLiteral ::= Parser[AstNode] = LBRACKET repsep(expression, SEPARATOR) opt(SEPARATOR) RBRACKET
fqcn ::= ident (DOT ident)*
oneLine ::= regex(""".*(\r\n|\r|\n|$)""".r)
hereDocument ::= ("""<<[a-zA-Z_][a-zA-Z0-9_]*""".r >> { t =>
val tag = t.substring(2)
Parser{in =>
val Success(temp, rest) = oneLine(in)
val line = new CharSequenceReader(temp, 0)
hereDocumentBody(tag).apply(rest) match {
case Success(value, next) =>
val source = cat(line, next)
Success(StringNode(NoLocation, value), source)
case Failure(msg, next) => Failure(msg, cat(line, next))
case Error(msg, next) => Error(msg, cat(line, next))
}
}
}) <~ SPACING_WITHOUT_LF
def hereDocumentBody(beginTag: String): Parser[String] = oneLine >> {line =>
if(beginTag == line.trim) "" else hereDocumentBody(beginTag) ^^ {result =>
line + result
}
}
ident ::= """[A-Za-z_][a-zA-Z0-9]*"""r
assignment ::= ident EQ expression
// val_declaration ::= "val" ident "=" expression
val_declaration ::= (VAL ident opt(typeAnnotation) EQ expression
// anonnymousFunction ::= "(" [param {"," param}] ")" "=>" expression
anonymousFunction ::= opt(LPAREN repsep(ident opt(typeAnnotation), COMMA) RPAREN) ARROW expression
// newObject ::= "new" fqcn "(" [param {"," param} ")"
newObject ::= NEW fqcn opt(LPAREN repsep(ident, COMMA) RPAREN)
## 関数定義
// functionDefinition ::= "def" ident ["(" [param {"," param]] ")"] "=" expression
functionDefinition ::= DEF ident opt(LPAREN repsep(ident opt(typeAnnotation), COMMA) RPAREN opt(typeAnnotation) EQ expression
defから始まる。
parse ::= lines
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment