├── test
├── parser_assignment.asl
├── parser_negation.asl
├── parser_waituntil.asl
├── tokenizer_code.asl
├── tokenizer_if.asl
├── parser_array.asl
├── parser_exitwith.asl
├── parser_expression_array.asl
├── tokenizer_expr.asl
├── tokenizer_while.asl
├── parser_binary_buildin_func.asl
├── parser_expression2.asl
├── parser_null_buildin_func.asl
├── parser_unary_buildin_func.asl
├── tokenizer_identifier.asl
├── parser_assign_result.asl
├── tokenizer_foreach.asl
├── tokenizer_for.asl
├── parser_func_params.asl
├── parser_try_catch.asl
├── parser_code.asl
├── tokenizer_func.asl
├── tokenizer_preprocessor.asl
├── parser_expression.asl
├── tokenizer_mask.asl
├── parser_operator.asl
├── parser_func_call.asl
├── tokenizer_switch.asl
├── tokenizer_var.asl
├── bugfix_unary_func_format.asl
└── types
├── .gitignore
├── tools
├── ASL GUI.exe
├── README.md
└── asl.xml
├── run
├── run_tests
├── src
├── types
│ ├── loader_test.go
│ └── loader.go
├── parser
│ ├── parser_helper.go
│ ├── parser_test.go
│ └── parser.go
├── main
│ └── asl.go
└── tokenizer
│ ├── tokenizer_test.go
│ └── tokenizer.go
├── CHANGELOG.md
├── LICENSE
├── README.md
└── types
/test/parser_assignment.asl:
--------------------------------------------------------------------------------
1 | x = 1;
--------------------------------------------------------------------------------
/test/parser_negation.asl:
--------------------------------------------------------------------------------
1 | var x = !foo();
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 | /pkg/
3 | /out/
4 | /in/
5 |
--------------------------------------------------------------------------------
/test/parser_waituntil.asl:
--------------------------------------------------------------------------------
1 | waituntil(x = x+1; x < 100);
2 |
--------------------------------------------------------------------------------
/test/tokenizer_code.asl:
--------------------------------------------------------------------------------
1 | var x = code("var x = 5;");
2 |
--------------------------------------------------------------------------------
/test/tokenizer_if.asl:
--------------------------------------------------------------------------------
1 | if a < b {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/test/parser_array.asl:
--------------------------------------------------------------------------------
1 | var x = [1, 2, 3];
2 | var y = x[1];
3 |
--------------------------------------------------------------------------------
/test/parser_exitwith.asl:
--------------------------------------------------------------------------------
1 | exitwith {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/test/parser_expression_array.asl:
--------------------------------------------------------------------------------
1 | var x = [1, 2, 3]-[2, 3];
2 |
--------------------------------------------------------------------------------
/test/tokenizer_expr.asl:
--------------------------------------------------------------------------------
1 | x = ((1+2+3)*4/2)+foo(1, 2, 3);
2 |
--------------------------------------------------------------------------------
/test/tokenizer_while.asl:
--------------------------------------------------------------------------------
1 | while true {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/test/parser_binary_buildin_func.asl:
--------------------------------------------------------------------------------
1 | setHit(someCar)("motor", 1);
2 |
--------------------------------------------------------------------------------
/test/parser_expression2.asl:
--------------------------------------------------------------------------------
1 | var x = true || (3 >= 4 && 5 < 8);
2 |
--------------------------------------------------------------------------------
/test/parser_null_buildin_func.asl:
--------------------------------------------------------------------------------
1 | var _volume = radioVolume();
2 |
--------------------------------------------------------------------------------
/test/parser_unary_buildin_func.asl:
--------------------------------------------------------------------------------
1 | var _isReady = unitReady(soldier);
2 |
--------------------------------------------------------------------------------
/test/tokenizer_identifier.asl:
--------------------------------------------------------------------------------
1 | var format = "should not be for mat!";
2 |
--------------------------------------------------------------------------------
/test/parser_assign_result.asl:
--------------------------------------------------------------------------------
1 | var x = foo(1, 2, 3);
2 | y = bar(1, 2, 3);
3 |
--------------------------------------------------------------------------------
/test/tokenizer_foreach.asl:
--------------------------------------------------------------------------------
1 | foreach unit => allUnits {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/test/tokenizer_for.asl:
--------------------------------------------------------------------------------
1 | for var i = 0; i < 100; i = i+1 {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/test/parser_func_params.asl:
--------------------------------------------------------------------------------
1 | func myFunc(a = 1, b = 2) {
2 | return a+b;
3 | }
4 |
--------------------------------------------------------------------------------
/test/parser_try_catch.asl:
--------------------------------------------------------------------------------
1 | try {
2 | // ...
3 | } catch {
4 | // ...
5 | }
6 |
--------------------------------------------------------------------------------
/tools/ASL GUI.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kugelschieber/asl/HEAD/tools/ASL GUI.exe
--------------------------------------------------------------------------------
/test/parser_code.asl:
--------------------------------------------------------------------------------
1 | var inline_code = code("var a = 1;var b = 2;if a < b {foo();}");
2 |
--------------------------------------------------------------------------------
/test/tokenizer_func.asl:
--------------------------------------------------------------------------------
1 | func TestFunction(param0, param1) {
2 | return true;
3 | }
4 |
--------------------------------------------------------------------------------
/test/tokenizer_preprocessor.asl:
--------------------------------------------------------------------------------
1 | #define HELLO_WORLD "Hello World!"
2 | hint(HELLO_WORLD);
3 |
--------------------------------------------------------------------------------
/test/parser_expression.asl:
--------------------------------------------------------------------------------
1 | var x = -(1+(2+3))/(6*(someVariable+99-100))-(20)+!anotherVariable+foo();
2 |
--------------------------------------------------------------------------------
/test/tokenizer_mask.asl:
--------------------------------------------------------------------------------
1 | var x = "Hello \"World\"";
2 | var y = code("var z = \"Hello \\"World\\"\";");
3 |
--------------------------------------------------------------------------------
/test/parser_operator.asl:
--------------------------------------------------------------------------------
1 | if x == y && x != y && x <= y && x >= y && x < y && x > y {
2 | // ...
3 | }
4 |
--------------------------------------------------------------------------------
/test/parser_func_call.asl:
--------------------------------------------------------------------------------
1 | func myFunc(a, b) {
2 | return a > b;
3 | }
4 |
5 | myFunc(1+3/4, 2-(66*22)/3-((123)));
6 |
--------------------------------------------------------------------------------
/test/tokenizer_switch.asl:
--------------------------------------------------------------------------------
1 | switch x {
2 | case 1:
3 | x = 1;
4 | case 2:
5 | x = 2;
6 | default:
7 | x = 3;
8 | }
9 |
--------------------------------------------------------------------------------
/test/tokenizer_var.asl:
--------------------------------------------------------------------------------
1 | // single line comment
2 |
3 | /*
4 | multi
5 | line
6 | comment
7 | */
8 |
9 | var x = 1;
10 | var array = [1, 2, 3];
11 |
--------------------------------------------------------------------------------
/run:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export GOROOT=/usr/local/go
4 | export PATH=$PATH:$GOROOT/bin
5 | export GOPATH=/home/marvin/Projekte/asl
6 | go run src/main/asl.go $1 $2
7 |
--------------------------------------------------------------------------------
/test/bugfix_unary_func_format.asl:
--------------------------------------------------------------------------------
1 | format("%1 %2", "value1", "value2"); // must result in format [...];
2 | someFunc("a", "b", "c"); // must result in ... call someFunc;
3 |
--------------------------------------------------------------------------------
/run_tests:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export GOROOT=/usr/local/go
4 | export PATH=$PATH:$GOROOT/bin
5 | export GOPATH=/home/marvin/Projekte/asl
6 | go test parser tokenizer types
7 |
--------------------------------------------------------------------------------
/src/types/loader_test.go:
--------------------------------------------------------------------------------
1 | package types_test
2 |
3 | import (
4 | "testing"
5 | "types"
6 | )
7 |
8 | func TestTypesGetFunction(t *testing.T) {
9 | if err := types.LoadTypes("../../test/types"); err != nil {
10 | t.Error(err)
11 | }
12 |
13 | function := types.GetFunction("hint")
14 |
15 | if function == nil {
16 | t.Error("Function 'hint' not found in type list")
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | **1.2.2**
4 |
5 | * bugfix: deadlock on compiling multile files at once
6 |
7 | **1.2.1**
8 |
9 | * bugfix: new line after while for pretty printing
10 | * bugfix: build in unary function with multiple arguments
11 |
12 | **1.2.0**
13 |
14 | * better error output
15 | * concurrent compiling
16 | * errors are handled per file and won't stop the whole compilation
17 | * function name check for build in functions
18 | * simpler syntax for "null" and unary buildin functions
19 |
20 | **1.1.1**
21 |
22 | * arrays can now be declared within expressions
23 | * code keyword bug fix
24 |
25 | **1.1.0**
26 |
27 | * changed syntax of foreach
28 | * private function variables
29 | * default values for function parameters
30 | * added preprocessor
31 | * code inlining using new keyword "code"
32 | * some code and repo cleanup
33 |
34 | **1.0.0**
35 |
36 | * first release
37 |
--------------------------------------------------------------------------------
/tools/README.md:
--------------------------------------------------------------------------------
1 | #ASL Tools
2 | A visual tool set to ease the work of asl developers.
3 | Maintained by yours truly: [654wak654](https://github.com/654wak654/)
4 |
5 | **Notepad++ Syntax Higligthing**: https://github.com/DeKugelschieber/asl/blob/master/tools/asl.xml
6 |
7 | Feel free to contribute with another text editor's syntax higligthing plugin.
8 |
9 | ##ASL GUI
10 | An optional Java interface to make the compile procces of ASL faster and more user-friendly. It's released under the MIT licence just like the core project. It also helps with error reporting of asl.
11 |
12 | **Version 1.1.0.0**
13 | - New Arma 3-themed look, and error reporting straight from asl.
14 | - Program now depends on asl.exe, they need to be in the same directory.
15 |
16 | **Version 1.0.0.0**
17 | - More style changes and bug fixes, marked ready for release.
18 |
19 | **Version 0.3.0.0:**
20 | - Fixed some possible bugs, did some style fixes and other code adjustments. It's now is readable without getting cataracts. Mostly anyway...
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Marvin Blum
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/parser/parser_helper.go:
--------------------------------------------------------------------------------
1 | package parser
2 |
3 | import (
4 | "errors"
5 | "strconv"
6 | "tokenizer"
7 | )
8 |
9 | type Compiler struct {
10 | tokens []tokenizer.Token
11 | tokenIndex int
12 | out string
13 | offset int
14 | pretty bool
15 | }
16 |
17 | // Initilizes the parser.
18 | func (c *Compiler) initParser(token []tokenizer.Token, prettyPrinting bool) bool {
19 | if len(token) == 0 {
20 | return false
21 | }
22 |
23 | c.tokens = token
24 | c.tokenIndex = 0
25 | c.out = ""
26 | c.offset = 0
27 | c.pretty = prettyPrinting
28 |
29 | return true
30 | }
31 |
32 | // Returns true, if current token matches expected one.
33 | // Does not throw parse errors and checks if token is available.
34 | func (c *Compiler) accept(token string) bool {
35 | return c.tokenIndex < len(c.tokens) && c.tokenEqual(token, c.get())
36 | }
37 |
38 | // Hard version of "accept".
39 | // Throws if current token does not match expected one.
40 | func (c *Compiler) expect(token string) {
41 | if !c.tokenEqual(token, c.get()) {
42 | panic(errors.New("Parse error, expected '" + token + "' but was '" + c.get().Token + "' in line " + strconv.Itoa(c.get().Line) + " at " + strconv.Itoa(c.get().Column)))
43 | }
44 |
45 | c.next()
46 | }
47 |
48 | // Returns true, if the next token matches expected one.
49 | // Does not throw parse errors and checks if token is available.
50 | func (c *Compiler) seek(token string) bool {
51 | if c.tokenIndex+1 >= len(c.tokens) {
52 | return false
53 | }
54 |
55 | return c.tokenEqual(token, c.tokens[c.tokenIndex+1])
56 | }
57 |
58 | // Increases token counter, so that the next token is compared.
59 | func (c *Compiler) next() {
60 | c.tokenIndex++
61 | }
62 |
63 | // Returns current token or throws, if no more tokens are available.
64 | func (c *Compiler) get() tokenizer.Token {
65 | if c.tokenIndex >= len(c.tokens) {
66 | panic(errors.New("No more tokens"))
67 | }
68 |
69 | return c.tokens[c.tokenIndex]
70 | }
71 |
72 | // Returns true if the end of input code was reached.
73 | func (c *Compiler) end() bool {
74 | return c.tokenIndex == len(c.tokens)
75 | }
76 |
77 | // Checks if two strings match.
78 | func (c *Compiler) tokenEqual(a string, b tokenizer.Token) bool {
79 | return a == b.Token
80 | }
81 |
82 | // Appends the output string to current SQF code output.
83 | func (c *Compiler) appendOut(str string, newLine bool) {
84 | c.out += str
85 |
86 | if newLine && c.pretty {
87 | c.out += "\r\n"
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/types/loader.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "io/ioutil"
5 | "strings"
6 | )
7 |
8 | const (
9 | // type for object types
10 | TYPE = 1
11 | NAN = "NaN"
12 | ARRAY = "ARRAY"
13 |
14 | // types for functions
15 | NULL = 2
16 | UNARY = 3
17 | BINARY = 4
18 |
19 | win_new_line = "\r\n"
20 | unix_new_line = "\n"
21 | )
22 |
23 | type FunctionType struct {
24 | Name string
25 | Type int // one of the constants NULL, UNARY, BINARY
26 | ArgsLeft int
27 | ArgsRight int // number of args on left side for binary functions
28 | }
29 |
30 | var functions []FunctionType
31 |
32 | // Returns function type information by name.
33 | // If not found, the parameter will be nil.
34 | func GetFunction(name string) *FunctionType {
35 | name = strings.ToLower(name)
36 |
37 | for _, function := range functions {
38 | if function.Name == name {
39 | return &function
40 | }
41 | }
42 |
43 | return nil
44 | }
45 |
46 | // Loads type information from file.
47 | // The format is specified by 'supportInfo' command: https://community.bistudio.com/wiki/supportInfo
48 | func LoadTypes(path string) error {
49 | content, err := ioutil.ReadFile(path)
50 |
51 | if err != nil {
52 | return err
53 | }
54 |
55 | data := strings.Replace(win_new_line, unix_new_line, string(content), -1) // make this work on windows and unix
56 | functions = make([]FunctionType, 0)
57 | parseTypes(data)
58 |
59 | return nil
60 | }
61 |
62 | func parseTypes(content string) {
63 | lines := strings.Split(content, unix_new_line)
64 |
65 | for _, line := range lines {
66 | if len(line) < 3 {
67 | continue
68 | }
69 |
70 | if line[0] == 'n' {
71 | parseNullFunction(line)
72 | } else if line[0] == 'u' {
73 | parseUnaryFunction(line)
74 | } else if line[0] == 'b' {
75 | parseBinaryFunction(line)
76 | }
77 | }
78 | }
79 |
80 | func parseNullFunction(line string) {
81 | parts := getParts(line)
82 | functions = append(functions, FunctionType{parts[0], NULL, 0, 0})
83 | }
84 |
85 | func parseUnaryFunction(line string) {
86 | parts := getParts(line)
87 |
88 | if len(parts) < 2 {
89 | return
90 | }
91 |
92 | args := getArgs(parts[1])
93 |
94 | var argsCount int
95 |
96 | if args[0] != ARRAY {
97 | argsCount = len(args) - getNaNArgs(args)
98 | }
99 |
100 | functions = append(functions, FunctionType{parts[0], UNARY, argsCount, 0})
101 | }
102 |
103 | func parseBinaryFunction(line string) {
104 | parts := getParts(line)
105 |
106 | if len(parts) < 3 {
107 | return
108 | }
109 |
110 | argsLeft := getArgs(parts[0])
111 | argsRight := getArgs(parts[2])
112 |
113 | var argsLeftCount int
114 | var argsRightCount int
115 |
116 | if argsLeft[0] != ARRAY {
117 | argsLeftCount = len(argsLeft) - getNaNArgs(argsLeft)
118 | }
119 |
120 | if argsRight[0] != ARRAY {
121 | argsRightCount = len(argsRight) - getNaNArgs(argsRight)
122 | }
123 |
124 | functions = append(functions, FunctionType{parts[1], BINARY, argsLeftCount, argsRightCount})
125 | }
126 |
127 | func getParts(line string) []string {
128 | line = line[2:]
129 | return strings.Split(line, " ")
130 | }
131 |
132 | func getArgs(part string) []string {
133 | return strings.Split(part, ",")
134 | }
135 |
136 | func getNaNArgs(args []string) int {
137 | nan := 0
138 |
139 | for _, arg := range args {
140 | if arg == NAN {
141 | nan++
142 | }
143 | }
144 |
145 | return nan
146 | }
147 |
--------------------------------------------------------------------------------
/src/main/asl.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "os"
7 | "parser"
8 | "path/filepath"
9 | "strings"
10 | "tokenizer"
11 | "types"
12 | )
13 |
14 | const (
15 | version = "1.2.2"
16 | extension = ".asl"
17 | sqfextension = ".sqf"
18 | typeinfo = "types"
19 | PathSeparator = string(os.PathSeparator)
20 | )
21 |
22 | type ASLFile struct {
23 | in string
24 | out string
25 | newname string
26 | }
27 |
28 | var (
29 | recursive bool = false
30 | pretty bool = false
31 | exit bool = false
32 | aslFiles []ASLFile
33 | inDir string
34 | )
35 |
36 | func usage() {
37 | fmt.Println("Usage: asl [-v|-r|-pretty|--help]