diff --git a/godel-script/README.md b/godel-script/README.md new file mode 100644 index 00000000..16935f07 --- /dev/null +++ b/godel-script/README.md @@ -0,0 +1,91 @@ +# GödelScript + +## Content + +* 简介 | [Introduction](#introduction) +* 文档 | [Documents](#documents) +* 编译 | [Compilation](#compilation) +* 用法 | [Usage](#usage) + +## Introduction + +GödelScript is designed for creating code analysis libraries and programs, +and compiling them to soufflé more easily. With it's Object-Oriented features, +it has great maintainability and readability. + +```rust +@output +pub fn hello() -> string { + return "Hello World!" +} +``` + +## Documents + +* GödelScript Language Reference + * GödelScript [Program](./docs/language-reference/program.md) + * GödelScript [Type](./docs/language-reference/type.md) + * GödelScript [Schema](./docs/language-reference/schemas.md) + * GödelScript [Database](./docs/language-reference/databases.md) + * GödelScript [Enum](./docs/language-reference/enums.md) + * GödelScript [Impl](./docs/language-reference/impl.md) + * GödelScript [Function](./docs/language-reference/functions.md) + * GödelScript [Import](./docs/language-reference/import.md) + * GödelScript [Query](./docs/language-reference/queries.md) + * GödelScript [Statement](./docs/language-reference/functions.md#statement) + * GödelScript [Expression](./docs/language-reference/functions.md#expression) +* GödelScript [Query Example](./example) +* GödelScript [Syntax Definition](./docs/syntax.md) + +## Compilation + +Structure of this project: + +``` +. +|-- dockerFile +|-- docs godel-script documents +|-- godel-backend godel-script backend +| |-- extension godel-script souffle extension +| |-- souffle souffle source code +| +-- tools souffle build tools ++-- godel-frontend godel-script frontend + +-- src godel-frontend source code +``` + +Need C++ standard at least `-std=c++17`. + +### Build Godel Script + +Use command below: + +```bash +mkdir build +cd build +cmake .. +make -j +``` + +After building, you'll find `build/godel` in the `build` folder. + +## Usage + +Use this command for help: + +> ./build/godel -h + +### Compile Target Soufflé + +> ./build/godel -p {godel library directory} {input file} -s {soufflé output file} -Of + +`-Of` is an optimization for join order, we suggest to switch it on. + +### Directly Run Soufflé + +> ./build/godel -p {godel library directory} {input file} -r -Of -f {database directory} + +`-Of` is an optimization for join order, we suggest to switch it on. + +`-r` means directly run soufflé. + +`-v` could be used for getting verbose info. diff --git a/godel-script/docs/language-reference/databases.md b/godel-script/docs/language-reference/databases.md new file mode 100644 index 00000000..609384e6 --- /dev/null +++ b/godel-script/docs/language-reference/databases.md @@ -0,0 +1,50 @@ +# GödelScript Database + +Back to [README.md](../../README.md#documents) + +## Declaration + +```rust +database School { + student: *Student, + classes: *Class as "class" + ... +} +``` + +Tables in databases should be set type, which uses `*` before the type name. +And the table type must be `schema`. +And for table name `student`, when running soufflé directly, we read sqlite database +using the same table name. + +If the table name conflicts with a keyword, try using `as "real_table"`, and +GödelScript will find the data from sqlite table `real_table`. + +## Initializing + +Database has a native method `fn load(dbname: string) -> Self`. +The argument string must be a string literal. + +```rust +fn default_db() -> School { + return School::load("example_db_school.db") // must use string literal +} +``` + +Then GödelScript will give you the input database. + +## Get Schema From Database + +It's quite easy to fetch schema data from database. +For example in `Student::__all__(db: School) -> *School`, +we could fetch the data by directly using `db.student`. + +```rust +impl Student { + pub fn __all__(db: School) -> *Student { + return db.student + } +} +``` + +Back to [README.md](../../README.md#documents) \ No newline at end of file diff --git a/godel-script/docs/language-reference/enums.md b/godel-script/docs/language-reference/enums.md new file mode 100644 index 00000000..4011f5d3 --- /dev/null +++ b/godel-script/docs/language-reference/enums.md @@ -0,0 +1,25 @@ +# GödelScript Enum + +Back to [README.md](../../README.md#documents) + +## Declaration + +```rust +enum Status { + exited, // 0 + running, // 1 + suspend // 2 +} +``` + +Usage: + +```rust +fn example() -> Status { + Status::exited + Status::running + Status::suspend +} +``` + +Back to [README.md](../../README.md#documents) diff --git a/godel-script/docs/language-reference/functions.md b/godel-script/docs/language-reference/functions.md new file mode 100644 index 00000000..39b14ecc --- /dev/null +++ b/godel-script/docs/language-reference/functions.md @@ -0,0 +1,360 @@ +# GödelScript Function + +Back to [README.md](../../README.md#documents) + +## Content + +* Function [Declaration](#function-declaration) +* Function [Implement](#function-implement) +* [Statement](#statement) +* [Expression](#expression) + +## Function Declaration + +GödelScript function declaration should include parameters, type of parameters +and the return type. +Only `main` function does not need return type. + +```rust +fn func_name(param0: int, param1: string) -> ReturnValueType {...} + +// deprecated +fn main() {...} +``` + +All the functions muse be [implemented](#function-implement)。 + +## Function Implementation + +Implement functions: + +```rust +fn func_name(param0: int, param1: string) -> int { + return param0 + param1.to_int() +} +``` + +Multiple statements in the same code block has the `or` condition. +They do not share variables and conditions through each other. And the execution +is not ordered (scheduled by soufflé). + +## Statement + +GödelScript supports the following statements: + +* [For Statement](#for-statement) +* [Let Statement](#let-statement) +* [Condition Statement](#condition-statement) +* [Match Statement](#match-statement) +* [Fact Statement(Experimental Feature)](#fact-statement) +* [Return Statement](#return-statement) + +Here's an example for nested statements +```rust +for(...) { + let (...) { + if (...) { + return true + } + } + let (...) { + if (...) { + return false + } + } +} +``` + +### For Statement + +For statement is used to define a variable from a set/collection. +Initialization expression is used after keyword `in`, and the type must be a set. +Initialization order is from left to right. + +```rust +for (a in Annotation(db), c in Class(db), m in Method(db)) { + ... +} +``` + +### Let Statement + +Let statement is used to define a variable initialized by single value. +initial value after `=` must not be a set type. +Initialization order is from left to right. + +```rust +let (file = c.getLocation.getFile(), anno = a.getName(), line = 1004) { + ... +} +``` + +### Condition Statement + +Condition statement does not support `else`, for the reason that this branch +often causes `ungrounded error` in soufflé. + +```rust +if (xxxxx) { + ... +} +``` + +### Match Statement + +Match statement requires the matched variable/value is type of `int` or `string`. +And must use literals for matching. + +```rust +match(type) { + 0 => if (anno.contains("a")) { + return true + }, + 1 => return false, + 2 => for(b: BinaryOperator in BinaryOperator(db)) { + if (b.getOperatorType() = "+") { + return true + } + } +} +``` + +### Fact Statement + +Fact statement is used to generate a collection of temporary data. +Once it is used in the function, other statements are not allowed. +All the data inside the fact statement must be `int` or `string` literals. +And each record of data must satisfy the parameter list: + +```rust +fn multi_input_test(a: int, b: string, c: int) -> bool { + [{1, "1", 1}, + {2, "2", 2}, + {3, "3", 3}, + {4, "4" ,4}] +} + +@output +fn out(a: int) -> bool { + for(num in int::range(0, 100)) { + if (multi_input_test(num, num.to_string(), num) && a = num) { + return true + } + } +} +``` + +### Return Statement + +Return statement uses two keywords, and values are required after them. + +```rust +return 0 // for return of single return type +yield 0 // for return of set return type +``` + +`return` is often used for return single value: + +```rust +fn get() -> int { + return 0 +} +``` + +`yield` is only allowed to return a set of value: + +```rust +fn int_set() -> *int { + yield 0 + yield 1 + yield 2 +} + +fn getm() -> *int { + // fn int_set() -> *int; + yield int_set() + yield 3 + yield 4 +} +``` + +## Expression + +GödelScript supports the following expressions: + +* [Call Expression](#call-expression) +* [Binary Operator](#binary-operator) + * [Mathematic Operator](#mathematic-operator) + * [Compare Operator](#compare-operator) + * [Logic Operator](#logic-operator) +* [Unary Operator](#unary-operator) + +### Call Expression + +Main components of call expressions are as follows: + +* First Expression + * [Function Call](#function-call) + * [Literal | Bracketed Expression](#literal-or-bracketed-expression) + * [Initializer List(Struct Expression)](#initializer-list) +* [Field Call](#field-call) +* [Path Call](#path-call) + +#### Function Call + +GödelScript function call is the same as other programming languages: + +```rust +global_function(arg0, arg1, arg2) +``` + +#### Literal or Bracketed Expression + +GödelScript Literal includes `int` `string` `float` `bool` literals. +These literals could be used as the first expression in call chains: + +```rust +fn example() -> *int { + yield "hello".len() + yield 1.add(2).sub(4) + yield "123".to_int().add(0) +} +``` + +Also bracketed expressions are allowed to be the first expression: + +```rust +fn example() -> *int { + yield ("hello" + "world").len() + yield (1 + 0).add(2).sub(4) +} +``` + +#### Initializer List + +GödelScript allows initializer for creating schema instance, +but the precondition is that this instance should be in the universal set of +the schema. +Initialization order of fields is not required. + +```rust +schema Student { + @primary id: int, + name: string +} + +impl Student { + pub fn __all__(db: DB) -> *Student { + return db.students + } +} + +fn example() -> Student { + return Student {id: 0, name: "xxx"} +} +``` + +#### Field Call + +Field call using `.`: + +1. get field from schema instance +```rust +fn example(stu: Student) -> string { + return stu.name + // ^^^^^ +} +``` +2. get table from database instance +```rust +impl Student { + @data_constraint + fn __all__(db: DB) -> *Student { + return db.students + // ^^^^^^^^^ + } +} +``` +3. call method from basic type instance or schema instance +```rust +fn example() -> *int { + yield 1.add(2) + // ^^^^^^^ + yield Student {id: 0, name: "xxx"}.getId() + // ^^^^^^^^ +} +``` + +#### Path Call + +Path call using `::`: + +1. call static method from schema +```rust +impl Student { + fn type() -> string { + return "Student" + } +} + +fn example() -> string { + return Student::type() + // ^^^^^^^^ +} +``` +2. call load method from database: `load(str: string) -> database` +```rust +fn example() -> *int { + let (db = DB::load("example_src.db")) { + // ^^^^^^^^^^^^^^^^^^^^^^^^ + for(stu in Student(db)) { + yield stu.id + } + } +} +``` +3. get member from enum +```rust +enum Status { + running, + suspend +} + +fn example() -> int { + Status::running + // ^^^^^^^^^ + Status::suspend + // ^^^^^^^^^ +} +``` + +### Binary Operator + +#### Mathematic Operator + +|`+`|`-`|`*`|`/`| +|:--|:--|:--|:--| +|add|sub|mul|div| + +#### Compare Operator + +Result must be `bool`. `=` will do binding operation if the left-value is not grounded when doing this +comparison, and this expression returns `true`. + +|`=`|`<`|`>`|`<=`|`>=`|`!=`| +|:--|:--|:--|:--|:--|:--| +|eq|lt|gt|le|ge|ne| + +#### Logic Operator + +|`&&`|`\|\|`| +|:--|:--| +|and|or| + +### Unary Operator + +|`!`|`-`| +|:--|:--| +|not|neg| + +Back to [README.md](../../README.md#documents) diff --git a/godel-script/docs/language-reference/impl.md b/godel-script/docs/language-reference/impl.md new file mode 100644 index 00000000..8f0de63e --- /dev/null +++ b/godel-script/docs/language-reference/impl.md @@ -0,0 +1,18 @@ +# GödelScript Impl + +Back to [README.md](../../README.md#documents) + +All functions in impl block should be implemented. + +```rust +impl SchemaA { + pub fn __all__(db: DB) -> *SchemaA { + ... + } + pub fn getName(self) -> string { + ... + } +} +``` + +Back to [README.md](../../README.md#documents) diff --git a/godel-script/docs/language-reference/import.md b/godel-script/docs/language-reference/import.md new file mode 100644 index 00000000..25b65a46 --- /dev/null +++ b/godel-script/docs/language-reference/import.md @@ -0,0 +1,102 @@ +# GödelScript Import/Use + +Back to [README.md](../../README.md#documents) + +## Content + +* [Import All Symbol](#import-all-symbol) +* [Partial Import](#partial-import) +* [Package Management](#package-management) + +## Import All Symbol + +```rust +use coref::java::* +``` + +## Partial Import + +```rust +use coref::java::{Annotation, Class, Method, JavaDB} +use coref::xml::XmlElement +``` + +## Package Management + +GödelScript package manager is enabled when command line arguments including +`-p {package dir path}`. + +### Path Mapping + +Package manager will scan the structure of given directory, finding all the files +with `.gdl` or `.gs`. Then mapping the relative path to package path. + +If illegal characters exist in relative path, for example `-`, or only numbers for +the file name, this path will not be accepted by package manager. But package +manager may not report error, instead, it will ignore them. + +If want to get the ignored relative paths, try using `-v` for verbose info. +Package manager will report these paths by using warning info. + +But if package path confliction occurs after scan, package manager will report +error and terminate the compilation process. + +### Example + +``` +Library +|-- coref.java.gdl +|-- coref.xml.gdl +|-- coref.python.gdl ++-- coref + |-- go.gdl + +-- a + +-- b.gdl + +=> + +coref::java +coref::xml +coref::python +coref::go +coref::a::b +``` + +Path confliction occurs in the example below: + +``` +Library +|-- coref +| |-- java.gdl +| +-- python.gdl ++-- coref.python.gdl + +=> + +coref::java +coref::python -- \ + > confliction occurs +coref::python -- / +``` + +Illegal characters detected in this example: + +``` +Library +|-- 0123.gdl +|-- my-godel-lib +| +-- js.gdl ++-- lib-file.123.gdl + +=> +0123 +^^^^ number + +my-godel-lib::js + ^ ^ character `-` included + +lib-file::123 + ^ ^^^ path segment including number and `-` +``` + +Back to [README.md](../../README.md#documents) diff --git a/godel-script/docs/language-reference/program.md b/godel-script/docs/language-reference/program.md new file mode 100644 index 00000000..0bd5c77d --- /dev/null +++ b/godel-script/docs/language-reference/program.md @@ -0,0 +1,111 @@ +# GödelScript Program + +Back to [README.md](../../README.md#documents) + +## Content +* 程序组成 | [Program Component](#program-component) +* 程序注释 | [Notes](#notes) +* 程序入口 | [Main](#main) + +## Program Component + +GödelScript programs may include: + +1. [package/symbol import](./import.md) +2. [enum declaration](./enums.md) +3. [schema declaration](./schemas.md) +4. [database declaration](./databases.md) +6. [schema method implementation](./impl.md) +7. [function declaration and implementation](./functions.md) +8. [query declaration](./queries.md) + +Here is an example including all the components mentioned above: + +```rust +// package import +use coref::java::{Annotation, JavaDB} + +// function declaration +fn default_db() -> JavaDB { + return JavaDB::load("example.db") +} + +// enum declaration +Enum status { + killed, + running, + suspend +} + +// schema declaration +Schema File { + @primary id: int +} + +// database declaration +database NewDB { + file: *File +} + +impl File { + pub fn __all__() -> *File { + yield File {id: 1} + yield File {id: 2} + } + + pub fn getId(self) -> int { + return self.id + } +} + +// query declaration +query get_all_anno from + anno in Annotation(default_db()) +select + anno.id as id +``` + +## Notes + +GödelScript uses C-like notes/comments。 + +```c +// single line comment + +/* + * multi line comment +*/ +``` + +## Main + +__[Warning] Deprecated: Better use `@output`__ + +Query output of GödelScript will output by main function. +Main function is the only one that does not need return value in GödelScript. + +Query output uses native function `output`. +This function only needs functions that you want to output the result as the argument. +And the argument function __does not need arguments__. +`output` can only be called in `main`. + +```rust +fn query_0(a: int, b: int) -> bool { + ... +} + +fn query_1(a: int, b: string) -> bool { + ... +} + +fn main() { + // output table structure: a (int) b (int) + output(query_0()) + + // output table structure: a (int) b (string) + output(query_1()) + ... +} +``` + +Back to [README.md](../../README.md#documents) \ No newline at end of file diff --git a/godel-script/docs/language-reference/queries.md b/godel-script/docs/language-reference/queries.md new file mode 100644 index 00000000..aa88e650 --- /dev/null +++ b/godel-script/docs/language-reference/queries.md @@ -0,0 +1,93 @@ +# GödelScript Query + +Back to [README.md](../../README.md#documents) + +## Query Name + +After keyword `query`, there requires a query name: + +```rust +query this_is_example_query +``` + +## From + +GödelScript query uses keyword `from` for variable definition. +Declared variables must be initialized, the way of initializing variables is the same +as in `for` statement. +But we do not need to consider whether the variable is a collection or not. + +Initialization is executed by order, so using variables before when initializing +other variables is allowed. + +```rust +from + anno in Annotation(db()), + class in Class(db()), + loc in class.getLocation() +``` + +## Where + +GödelScript query uses `where` with conditional expression for filtering data. + +```rust +where + anno = class.getAnnotation() && + loc.getFile().getRelativePath().contains(".java") +``` + +## Select + +GödelScript query uses `select` to generate the final result. +Each select data has an expression and it's corresponding column name after keyword `as`. If column name is not given, GödelScript will generate a random column name automatically. + +```rust +select + anno.getName() as annotationName, + loc.getFile() as fileName, + class.getName() // random column name: column_543771021 +``` + +The total query declaration is as follows: + +```rust +query this_is_example_query from + anno in Annotation(db()), + class in Class(db()), + loc in class.getLocation() +where + anno = class.getAnnotation() && + loc.getFile().getRelativePath().contains(".java") +select + anno.getName() as annotationName, + loc.getFile() as fileName, + class.getName() +``` + +And it is equivalent to: + +```rust +@output +fn this_is_example_query( + annotationName: string, + fileName: string, + column_543771021: string +) -> bool { + for(anno in Annotation(db()), class in Class(db())) { + let (loc in c.getLocation()) { + if (anno = c.getAnnotation() && + loc.getFile().getRelativePath().contains(".java")) { + if (annotationName = anno.getName() && + fileName = loc.getFile() && + column_543771021 = class.getName()) { + return true + } + } + } + } +} + +``` + +Back to [README.md](../../README.md#documents) diff --git a/godel-script/docs/language-reference/schemas.md b/godel-script/docs/language-reference/schemas.md new file mode 100644 index 00000000..f45fe6e0 --- /dev/null +++ b/godel-script/docs/language-reference/schemas.md @@ -0,0 +1,208 @@ +# GödelScript Schema + +Back to [README.md](../../README.md#documents) + +## Declaration + +Here's a schema declaration example, +the field declaration format is `field : type`, +primary key is annotated by `@primary`. + +```rust +schema Student { + @primary id: int, + name: string, + phone: string +} +``` + +## Initializing + +GödelScript requires universal set for schema. +We could simply think it as the constructor of schema. +The constructor is declared in `impl` block, and should be public. +GödelScript only accept `__all__` as the constructor. + +### From Database + +Schema's universal set could be fetched from a database: + +```rust +database DB { + students: *Student +} + +impl Student { + pub fn __all__(db: DB) -> *Student { + return db.students + } +} + +fn getStudents() -> *Student { + let (db = DB::load("example.db")) { + for (student in Student(db)) { + if (student.name.contains("von")) { + yield student + } + } + } +} +``` + +Inherited schema could use [this](#initializing-inherited-schema) to initialize. + +### From Initializer + +Schema's universal set could be initialized from initializers: + +```rust +impl Student { + pub fn __all__() -> *Student { + yield Student {id: 1, name: "zxj", phone: "11451419"} + yield Student {id: 2, name: "fxj", phone: "11451419"} + yield Student {id: 3, name: "lyn", phone: "11451419"} + } +} +``` + +This example also shows the feature of `initializer`, +by this way we could create a schema instance. +Although it's an instance created temporarily, this instance also should be +included in the universal set. Otherwise the creation is failed. + +In this example, the `initializer` is used in constructor, so all the created +instance must be included in universal set. + +## Inheritance + +### Inherit Fields + +Schema could be inherited, after inheritance, parent schema's fields will be +add at the front of the child schema structure. +All the inheritable methods will also be inherited from parent schema, except +`__all__`. + +```rust +schema Lee extends Student { + // parent fields added here. + + // @primary id: int, + // name: string, + // phone: string, + for_example: int +} +``` + +### Inherit Methods + +If parent schema has these two methods, child schema will inherit them. + +```rust +impl Student { + // method, first parameter is self, do not need type declaration. + fn getName(self) -> string { + return self.name + } + // static method, without self parameter + fn getType() -> string { + return "Student" + } +} +``` + +### Method Override + +GödelScript allows child schema implements methods that +having the same names of parent methods. +Methods of parent schema will be overridden. +Overridden methods share the same name, +but there's no need to share the same parameters and return type. + +```rust +impl Lee { + fn getType() -> string { + return "Lee Student" + } +} +``` + +### Initializing Inherited Schema + +We often initialize child schema by universal set of parent schema: + +```rust +schema Lee extends Student { + // @primary id: int, + // name: string, + // phone: string, + for_example: int +} + +impl Lee { + pub fn __all__(db: DB) -> *Lee { + // schema(db) will call schema::__all__(db), this is a syntactic sugar + // also it is correct to directly use schema::__all__(db) + for (parent in Student(db)) { + // ..parent here is a spread syntax + yield Lee { ..parent, for_example: 114 } + } + } +} +``` + +And from the example above, we use another initializer feature `spread`, +this syntax will expand the input schema instance. GödelScript only do duck-type +check for the schema instance, so if the structure is correct, the program is +correct. It is not a must to use parent schema to initialize... + +```rust +yield Lee { ..parent, for_example: 114 } +// this is equivalent to +// yield Lee { id: parent.id, name: parent.name, phone: parent.phone, for_example: 114 } +``` + +Here is an example, get `Class` in a specified file from universal set of `Class`, +by using inheritance: + +```rust +schema ClassInIDKFile extends Class {} + +impl ClassInIDKFile { + fn __all__(db: JavaDB) -> *ClassInIDKFile { + for(c in Class(db)) { + if (c.getLocation().getFile().getRelativePath() = "./com/xxx/xxx.java") { + yield ClassInIDKFile { ..c } + } + } + } +} +``` + +### Comparison and Type Casting + +#### `fn key_eq(self, T) -> bool` | `fn key_neq(self, T) -> bool` + +For primary key comparisons, require schemas having `int` type primary key. + +```rust +method.key_eq(function) +method.key_neq(function) +``` + +#### `fn to(self) -> T` + +Convert schema instance to another schema instance, duck type check. + +```rust +stmt.to() +``` + +#### `fn is(self) -> bool` + +Judge if this schema instance in universal set of another schema, duck type check. + +```rust +stmt.is() +``` + +Back to [README.md](../../README.md#documents) \ No newline at end of file diff --git a/godel-script/docs/language-reference/type.md b/godel-script/docs/language-reference/type.md new file mode 100644 index 00000000..5f097686 --- /dev/null +++ b/godel-script/docs/language-reference/type.md @@ -0,0 +1,112 @@ +# GödelScript Types + +Back to [README.md](../../README.md#documents) + +GödelScript reserved some symbols for basic types, +other types defined by users could also be used: + +* [Enum](./enums.md) +* [Schema](./schemas.md) +* [Database](./databases.md) + +Some type definitions like this below may also exists: + +```rust +*int +*string +*Annotation +``` + +Type with `*` means it is a __set__ type: + +```rust +*int // int set +*string // string set +*Annotation // schema Annotation set +``` + +## GödelScript Basic Types + +### Bool + +`bool` literal should be `true` or `false`. + +### String + +`string` includes these native methods: + +```rust +fn to_int(self: string) -> int; +fn substr(self: string, begin: int, length: int) -> string; +fn len(self: string) -> int; +fn get_regex_match_result(self: string, str: string, num: int) -> string; +fn matches(self: string, str: string) -> bool; +fn contains(self: string, str: string) -> bool; +fn ne(self: string, str: string) -> string; +fn eq(self: string, str: string) -> string; +fn add(self: string, str: string) -> string; +fn to_set(self) -> *string; +fn to_upper(self) -> string; +fn to_lower(self) -> string; +fn replace_all(self, pattern: string, replacement: string) -> string; +fn replace_once(self, pattern: string, replacement: string, index: int) -> string; +``` + +### Float + +`float` includes these native methods: + +```rust +fn rem(self: float, num: float) -> float; +fn pow(self: float, num: float) -> float; +fn le(self: float, num: float) -> float; +fn gt(self: float, num: float) -> float; +fn ne(self: float, num: float) -> float; +fn ge(self: float, num: float) -> float; +fn eq(self: float, num: float) -> float; +fn div(self: float, num: float) -> float; +fn sub(self: float, num: float) -> float; +fn mul(self: float, num: float) -> float; +fn lt(self: float, num: float) -> float; +fn add(self: float, num: float) -> float; +fn neg(self: float) -> float; +``` + +### Int + +`int` includes these native methods: + +```rust +fn bitxor(self: int, num: int) -> int; +fn bitor(self: int, num: int) -> int; +fn bitand(self: int, num: int) -> int; +fn rem(self: int, num: int) -> int; +fn pow(self: int, num: int) -> int; +fn le(self: int, num: int) -> int; +fn lt(self: int, num: int) -> int; +fn gt(self: int, num: int) -> int; +fn ne(self: int, num: int) -> int; +fn ge(self: int, num: int) -> int; +fn eq(self: int, num: int) -> int; +fn div(self: int, num: int) -> int; +fn mul(self: int, num: int) -> int; +fn sub(self: int, num: int) -> int; +fn add(self: int, num: int) -> int; +fn bitnot(self: int) -> int; +fn neg(self: int) -> int; +fn to_string(self: int) -> string; +fn range(begin: int, end: int) -> *int; +fn to_set(self) -> *int; +``` + +### Aggregator for Set Types + +```rust +fn len(self: *T) -> int; +fn sum(self: *int) -> int; +fn min(self: *int) -> int; +fn max(self: *int) -> int; +fn find(self: *T0, instance: T1) -> T0; +``` + +Back to [README.md](../../README.md#documents) \ No newline at end of file diff --git a/godel-script/docs/syntax.md b/godel-script/docs/syntax.md new file mode 100644 index 00000000..349399a5 --- /dev/null +++ b/godel-script/docs/syntax.md @@ -0,0 +1,248 @@ +# GödelScript Syntax + +Back to [README.md](../README.md#documents) + +GödelScript Syntax Spec, +Usage Document see [GödelScript Program](./language-reference/program.md)。 + +## Identifier / Literal / Annotation +```ebnf +identifier = (* basic token *); +number_literal = (* basic token *); +string_literal = (* basic token *); +literal = number_literal | string_literal; +``` + +## Annotation +```ebnf +prop_pair = identifier "=" string_literal; +annotation = + "@" identifier ["(" string_literal ")"] | + "@" identifier ["(" [prop_pair [{"," prop_pair}]] ")"]; +``` + +Example: + +```rust +this_is_an_identifier +12345 +"string literal" +``` + +Annotation example: + +```rust +@inline +fn get(a: Method) -> bool { + ... +} +``` + +## Program + +About main program, [Click](./language-reference/program.md)。 + +```ebnf +program = {use_stmt} { + {function_decl} | + {enum_decl} | + {schema_decl} | + {use_decl} | + {impl_decl} | + {database_decl} | + {query_decl} +}; +``` + +## Declaration + +### Function + +Function Usage [Documents](./language-reference/functions.md)。 + +```ebnf +function_decl = + [{annotation}] + "fn" id "(" [params] ")" ["->" type_def] + [ ";" | ("{" block_stmt "}")]; +params = param {"," param}; +param = identifier [":" param_type_def]; +param_type_def = ["*"] identifier; +block_stmt = {statement}; +``` + +### Enum + +Enum Usage [Documents](./language-reference/enums.md)。 + +```ebnf +enum_decl = "enum" identifier "{" [identifier {"," identifier}] "}"; +``` + +### Schema + +Schema Usage [Documents](./language-reference/schemas.md)。 + +```ebnf +schema_decl = + "schema" identifier ["extends" type_def] "{" [schema_members] "}"; +schema_members = schema_member {"," schema_member}; +schema_member = [anno] id ":" type_def; +``` + +### Database + +Database Usage [Documents](./language-reference/databases.md)。 + +```ebnf +database_decl = "database" identifier "{" [database_tables] "}"; +database_tables = database_table {"," database_table}; +database_table = identifier ":" type_def ["as" string_literal]; +``` + +### Use / Import + +Package Manager / Symbol Import +[Documents](./language-reference/import.md)。 + +```ebnf +use_stmt = "use" identifier {"::" identifier} ["::" ("*"|multi_use)]; +multi_use = "{" identifier {"," identifier} "}"; +``` + +### Implement + +Impl Usage [Documents](./language-reference/impl.md)。 + +```ebnf +impl_decl = "impl" identifier ["for" identifier] "{" {function_decl} "}"; +``` + +### GödelScript Query + +Query Usage [Documents](./language-reference/queries.md)。 + +```ebnf +query_decl = + "query" identifier + "from" from_list + ["where" or_expr] + "select" select_list; +from_list = from_def {"," from_def}; +from_def = identifier "in" or_expr; +select_list = select_column {"," select_column}; +select_column = or_expr ["as" identifier]; +``` + +## Statement + +GödelScript statement +[Documents](./language-reference/functions.md#statement)。 + +```ebnf +statement = + let_stmt | + cond_stmt | + for_stmt | + match_stmt | + fact_stmt | + ret_stmt | + in_block_expr; + +def = identifier [":" type_def]; +type_def = identifier ["::" identifier]; +``` + +### Let Statement +```ebnf +let_stmt = "let" "(" let_def ")" "{" [statement] "}"; +let_def = def "=" expression {"," def "=" expression}; +``` + +### Condition Statement +```ebnf +cond_stmt = if_stmt {elsif_stmt} [else_stmt]; +if_stmt = "if" "(" expression ")" "{" [statement] "}"; +elsif_stmt = "else" "if" "(" expression ")" "{" [statement] "}"; +else_stmt = "else" "{" [statement] "}"; +``` + +### For Statement +```ebnf +for_stmt = "for" "(" for_def ")" "{" [statement] "}"; +for_def = def "in" expression {"," def "in" expression}; +``` + +### Match Statement +```ebnf +match_stmt = "match" "(" expression ")" "{" [match_pairs] "}"; +match_pairs = match_pair {"," match_pair}; +match_pair = literal "=>" statement; +``` + +### Fact Statement +```ebnf +fact_stmt = "[" fact_data {"," fact_data} "]"; +fact_data = "{" + (number_literal | string_literal) + {"," (number_literal | string_literal)} +"}"; +``` + +### Return Statement +```ebnf +ret_stmt = ("return" | "yield") or_expr; +``` + +### In Block Expression (as Statement) +```ebnf +in_block_expr = expression; +``` + +## Expression + +GödelScript Expression [Documents](./language-reference/functions.md#expression)。 + +```ebnf +expression = or_expr; +``` + +### Calculation +```ebnf +or_expr = and_expr {"||" and_expr}; +and_expr = (not_expr | cmp_expr) {"&&" (not_expr | cmp_expr)}; +curved_expr = "(" or_expr ")"; +unary_expr = "-" (symcall | curved_calc_expr | unary_expr); +not_expr = "!" cmp_expr; +cmp_expr = + additive_expr + [("=" | "!=" | "<" | "<=" | ">" | ">=" | "in") additive_expr]; +additive_expr = multiple_expr {("+" | "-") multiple_expr}; +multiple_expr = + (symcall | curved_expr | unary_expr) + {("*" | "/") (symcall | curved_expr | unary_expr)}; +``` + +### Call Expression +```ebnf +symcall = symhead {sympath | symget}; +symhead = + identifier [initializer|funcall] + | literal + | curved_expr + ; +sympath = "::" identifier [funcall]; +symget = "." identifier [funcall]; + +funcall = "(" [arglist] ")"; +arglist = or_expr {"," or_expr}; +``` + +### Initializer + +Usage: [Initializer List](./language-reference/functions.md#initializer-list) + +```ebnf +initializer = "{" [initializer_pair ","] "}"; +initializer_pair = identifier ":" or_expr; +``` \ No newline at end of file