DEV Community

KiminLee
KiminLee

Posted on

GreenLight : Added a syntax checker feature!

Introduction

GreenLight is a new simple programming language created by Marc. 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

Getting start

There was a one good issue 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);
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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 '('
            });
Enter fullscreen mode Exit fullscreen mode

same for []

if (code[i].includes("[")) {
...
}
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

Now, we can catch the error!

Top comments (0)