GreenLight : Added a syntax checker feature!
Published: 2020-10-26 21:27:05

##Introduction
[GreenLight](https://github.com/PerhapsSomeone/GreenLight) is a new simple programming language created by [Marc](https://github.com/PerhapsSomeone). This new simple language can help to make CLI program much easier and faster. It takes all the good features from JAVASCRIPT and other many languages. 
__Variables:__
`var hello = "world"; // Mutable variable
const constant = "light"; // Constant variable`
__Objects/Array:__
`let array = [498, 49, 299, 18]; // Declare a new array
array[1] = 133; // Modify the second element of the array
print(array[1]); // Print the second element of the array
let object = { // Declare a new object...
  "key": "hello world"
};
print(object>>key); // Print the value located at the key "key"
`
It also, provides general __standard library__!
`sqrt(16); // => 4 Get the square root of a number
log(1); // => 0 Get the natural logarithm of a number
pow(2, 10); // => 1024 Raise a number to an arbitrary power
exp(1); // => 2.718281828459045 Get the exponential of a number
...
`
[More Info](https://github.com/PerhapsSomeone/GreenLight#documentation)

##Getting start
There was a one [good issue](https://github.com/PerhapsSomeone/GreenLight/issues/13) on this project. It didn't catch syntax errors and handle them properly. So, GreenLight decided to improve this feature and let someone help them. Luckily, I was there for help!

##Step 1: Testing
The first thing to do is always testing first! So I have run the demo `hello_world.gl` file. 
```
print("Welcome to GreenLight!");
print("Hello world!");
logError("I'm an error.");

print("---Cryptography---");
print("The SHA256 hash of 'Hello World' is " + sha256("Hello World") + "!");
print("The SHA3-256 hash of 'Hello World' is " + sha3("Hello World") + "!");

print("A random number between 50 and 100 is " + randomNumberBetween(50, 100));


print("---Array Functions---");

print("- Array Difference:");
const school_subjects = ['Math', 'Geography','History'];
var approved_school_subjects = ['Geography'];
const pending_subjects = arrDiff(school_subjects, approved_school_subjects);
print("The school subjects that still need approval are: " + pending_subjects);

print("- Array Difference Symmetric:");
const female_animals = ['Duck', 'Cat','Elephant','Tiger'];
var male_animals = ['Duck', 'Dog','Elephant','Tiger'];
const animals_alone = arrDiffSymmetric(female_animals, male_animals);
print("Animals that do not have a pair are: " + animals_alone);

print("- Array Intersection:");
const fruits = ['Banana', 'Apple', 'Grape', 'Strawberry'];
var fruits_find = ['Strawberry', 'Apple', 'Watermelon'];
const fruits_found = arrIntersect(fruits, fruits_find);
print("The fruits found were: " + fruits_found);
```
It was a simple code file, just printed some messages. After compiling this, it showed that the compilations is OK, and ready to run
```
[*] Executing lexer...
[OK] Lexer finished successfully!
[*] Transpiling...
[OK] Transpilation complete!
[*] Running syntax checker & linter...
[OK] Syntax checker finished, no issues found!
```
and following output message.
```
Welcome to GreenLight!
Hello world!
I'm an error.
---Cryptography---
The SHA256 hash of 'Hello World' is a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e!
The SHA3-256 hash of 'Hello World' is e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51!
A random number between 50 and 100 is 100
---Array Functions---
- Array Difference:
The school subjects that still need approval are: Math,History
- Array Difference Symmetric:
Animals that do not have a pair are: Cat,Dog
- Array Intersection:
The fruits found were: Apple,Strawberry
```
So far, it seems OK when we correctly write the code using GreenLight syntax. However, what if I intentionally break this?

So, I deleted the ')' on the first line `print("Welcome to GreenLight!");`. It turned out the program didn't catch the syntax error `UnhandledPromiseRejectionWarning: ReferenceError:`.

##Step 2: Spot the exact code file that should be improved!
To make an enhancement, I needed to find out which code file is dealing with syntax checking function among the dozens of `.js` code files. Luckily there is a hint from Marc and code itself. When I compiled the code, it showed that `[*] Transpiling...` is ahead of `[*] Running syntax checker & linter...` That means somehow the `Transpiling` process will transform the `.gl` file to '.js' file, and then it will run the `syntax checker`.

##Step 3: Inside `transpiler.js`
In the `transpiler.js` file, there is:
```
function runChecks() {
	return syntaxChecker.checkSyntax(code);
}
```
The "code" is already transformed to `.js` syntax. So, in this stage the "code" looks like
`console.log("Welcome to GreenLight!";print("Helloworld!");greenlight_internal_log_error("I'm an error.");console.log("---Cryptography---");
...`

As we can see, `console.log("Welcome to GreenLight!";` is not closed with ')'. 

##Step 4: Inside `syntax_checker.js`
In this file, there was no syntax checking feature. It only catched if the user-built function was properly called with `call`.   
```
function checkSyntax(compiledCode) {
	let checkPassed = true;
	let splitCode = compiledCode.split(" ");
	if (!checkAsyncFunctionCalls(splitCode)) checkPassed = false;

	return checkPassed;
}

function checkAsyncFunctionCalls(code) {
	let passed = true;
	let withinString = false;
	...
	return passed;
}
```

##Step 4: Added bracket checking feature
It is impossible for me to added all the syntax checking functions for the "GreenLight." So, I decided to specifically deal with open and close bracket syntax checker. First of all creating a function,
`checkParenthesesBracket` it should `return false` if the bracket doesn't open and close properly.

_For example)_
`({)}` false
`({[]})` true
`([[])` false

The `checkParenthesesBracket` takes code as parameter. The code was separated by whitespace, but it wouldn't be good idea for this. So It had to be separated by `;`. `let splitCode = compiledCode.split(";");` As a result, `code` is lines of the entire code.

For each line, `for (let i = 0; i < code.length; i++)` must have closing bracket if the open bracket is used.
```
if (code[i].includes("(")) {
			let flag = true; // check '(', ')' is a pair
			code[i].split("").forEach(char => {
				if (flag && char === "(") flag = false; // needs ')'
				if (!flag && char === ")") flag = true; // needs '('
			});
```

same for `[]` 
```
if (code[i].includes("[")) {
...
}
```

##Step 5: Testing and Wrap up
`if (!checkParenthesesBracket(splitCode)) checkPassed = false;` is added in the `checkSyntax` function right before `checkAsyncFunctionCalls`.

Now run the code again.
```
[*] Executing lexer...
[OK] Lexer finished successfully!
[*] Transpiling...
[OK] Transpilation complete!
[*] Running syntax checker & linter...
[WARN] '(' is not closed. This could cause syntax errors: console.log("Welcome to GreenLight!"
[WARN] Syntax checker found at least one issue in your code!
```
Now, we can catch the error!