├── Jhethia.jar ├── target ├── test-classes │ ├── hello1.jhethia │ └── hello_world.jhethia └── classes │ └── org │ └── prakarshs │ ├── Jhethia.class │ ├── JhethiaRun.class │ ├── Tokens │ ├── Token.class │ ├── TokenType.class │ └── Token$TokenBuilder.class │ ├── Parser │ ├── LexicalParser.class │ ├── StatementParser.class │ └── StatementParser$1.class │ ├── Constants │ └── ErrorConstants.class │ ├── Exceptions │ ├── JhethiaException.class │ ├── SyntaxException.class │ ├── ExecutionException.class │ └── OperationException.class │ └── Syntax │ ├── Statements │ ├── Statement.class │ ├── InputStatement.class │ ├── PrintStatement.class │ └── ConditionStatement.class │ └── Expressions │ ├── Expression.class │ └── Operators │ ├── NotOperator.class │ ├── AdditionOperator.class │ ├── DivisionOperator.class │ ├── EqualsOperator.class │ ├── LessThanOperator.class │ ├── OperatorExpression.class │ ├── GreaterThanOperator.class │ └── MultiplicationOperator.class ├── src ├── test │ └── resources │ │ ├── loop_example.jhethia │ │ ├── binary_search.jhethia │ │ ├── bubble_sort.jhethia │ │ └── calculator.jhethia └── main │ └── java │ └── org │ └── prakarshs │ ├── Syntax │ ├── Expressions │ │ ├── Expression.java │ │ ├── AssignExpression.java │ │ ├── Operators │ │ │ ├── OperatorExpression.java │ │ │ ├── UnaryOperatorExpression.java │ │ │ ├── BinaryOperatorExpression.java │ │ │ ├── ClassInstanceOperator.java │ │ │ ├── ArrayAppendOperator.java │ │ │ ├── NotOperator.java │ │ │ ├── AssignmentOperator.java │ │ │ ├── ModuloOperator.java │ │ │ ├── LogicalOrOperator.java │ │ │ ├── LogicalAndOperator.java │ │ │ ├── DivisionOperator.java │ │ │ ├── ExponentiationOperator.java │ │ │ ├── EqualsOperator.java │ │ │ ├── ClassInstanceOfOperator.java │ │ │ ├── NotEqualsOperator.java │ │ │ ├── SubtractionOperator.java │ │ │ ├── ClassCastOperator.java │ │ │ ├── FloorDivisionOperator.java │ │ │ ├── NestedClassInstanceOperator.java │ │ │ ├── LessThanOperator.java │ │ │ ├── GreaterThanOperator.java │ │ │ ├── LessThanOrEqualToOperator.java │ │ │ ├── GreaterThanOrEqualToOperator.java │ │ │ ├── ArrayValueOperator.java │ │ │ ├── MultiplicationOperator.java │ │ │ ├── AdditionOperator.java │ │ │ ├── Operator.java │ │ │ └── ClassPropertyOperator.java │ │ ├── ArrayExpression.java │ │ ├── VariableExpression.java │ │ ├── ClassExpression.java │ │ ├── FunctionExpression.java │ │ └── ExpressionReader.java │ ├── Values │ │ ├── LogicalValue.java │ │ ├── ComparableValue.java │ │ ├── IterableValue.java │ │ ├── NumericValue.java │ │ ├── NullValue.java │ │ ├── ThisValue.java │ │ ├── TextValue.java │ │ ├── Value.java │ │ ├── ArrayValue.java │ │ └── ClassValue.java │ └── Statements │ │ ├── FunctionStatement.java │ │ ├── Statement.java │ │ ├── ClassStatement.java │ │ ├── Loops │ │ ├── NextStatement.java │ │ ├── BreakStatement.java │ │ ├── WhileLoopStatement.java │ │ ├── IterableLoopStatement.java │ │ ├── ForLoopStatement.java │ │ └── AbstractLoopStatement.java │ │ ├── ExpressionStatement.java │ │ ├── PrintStatement.java │ │ ├── ReturnStatement.java │ │ ├── AssertStatement.java │ │ ├── RaiseExceptionStatement.java │ │ ├── CompositeStatement.java │ │ ├── ConditionStatement.java │ │ ├── InputStatement.java │ │ └── HandleExceptionStatement.java │ ├── Exceptions │ ├── SyntaxException.java │ ├── ExecutionException.java │ ├── OperationException.java │ └── JhethiaException.java │ ├── Context │ ├── definition │ │ ├── Definition.java │ │ ├── ClassDetails.java │ │ ├── FunctionDefinition.java │ │ ├── FunctionDetails.java │ │ ├── ClassDefinition.java │ │ ├── DefinitionContext.java │ │ └── DefinitionScope.java │ ├── NextScope.java │ ├── BreakScope.java │ ├── ReturnScope.java │ ├── NextContext.java │ ├── BreakContext.java │ ├── ReturnContext.java │ ├── MemoryContext.java │ ├── ClassInstanceContext.java │ ├── ValueReference.java │ ├── MemoryScope.java │ └── ExceptionContext.java │ ├── Constants │ └── ErrorConstants.java │ ├── Tokens │ ├── Token.java │ ├── TokenType.java │ └── TokensStack.java │ ├── JhethiaRun.java │ ├── Jhethia.java │ └── Parser │ ├── LexicalParser.java │ └── StatementParser.java ├── README.md └── pom.xml /Jhethia.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/Jhethia.jar -------------------------------------------------------------------------------- /target/test-classes/hello1.jhethia: -------------------------------------------------------------------------------- 1 | lijiye_baapuji ans 2 | dekhiye_baapuji ans -------------------------------------------------------------------------------- /src/test/resources/loop_example.jhethia: -------------------------------------------------------------------------------- 1 | chai_piyo i in 0..10 by 2 2 | dekhiye_baapuji "I is : "+i 3 | biscuit_khao -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Jhethia.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Jhethia.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/JhethiaRun.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/JhethiaRun.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Tokens/Token.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Tokens/Token.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Tokens/TokenType.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Tokens/TokenType.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Parser/LexicalParser.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Parser/LexicalParser.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Parser/StatementParser.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Parser/StatementParser.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Constants/ErrorConstants.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Constants/ErrorConstants.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Parser/StatementParser$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Parser/StatementParser$1.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Tokens/Token$TokenBuilder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Tokens/Token$TokenBuilder.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Exceptions/JhethiaException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Exceptions/JhethiaException.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Exceptions/SyntaxException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Exceptions/SyntaxException.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Statements/Statement.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Statements/Statement.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Exceptions/ExecutionException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Exceptions/ExecutionException.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Exceptions/OperationException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Exceptions/OperationException.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Expression.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Expression.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Statements/InputStatement.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Statements/InputStatement.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Statements/PrintStatement.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Statements/PrintStatement.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Statements/ConditionStatement.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Statements/ConditionStatement.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/NotOperator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/NotOperator.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/AdditionOperator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/AdditionOperator.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/DivisionOperator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/DivisionOperator.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/EqualsOperator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/EqualsOperator.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/LessThanOperator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/LessThanOperator.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/OperatorExpression.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/OperatorExpression.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/GreaterThanOperator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/GreaterThanOperator.class -------------------------------------------------------------------------------- /target/classes/org/prakarshs/Syntax/Expressions/Operators/MultiplicationOperator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakarshs/Jhethia/HEAD/target/classes/org/prakarshs/Syntax/Expressions/Operators/MultiplicationOperator.class -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Expression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions; 2 | 3 | import org.prakarshs.Syntax.Values.Value; 4 | 5 | public interface Expression { 6 | Value evaluate(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/AssignExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions; 2 | 3 | import org.prakarshs.Syntax.Values.Value; 4 | 5 | public interface AssignExpression { 6 | Value assign(Value value); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/LogicalValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | public class LogicalValue extends ComparableValue { 4 | public LogicalValue(Boolean value) { 5 | super(value); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/ComparableValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | public class ComparableValue> extends Value { 4 | public ComparableValue(T value) { 5 | super(value); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/OperatorExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Syntax.Expressions.Expression; 4 | 5 | public interface OperatorExpression extends Expression { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/IterableValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | public abstract class IterableValue extends Value implements Iterable> { 4 | public IterableValue(T value) { 5 | super(value); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Exceptions/SyntaxException.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Exceptions; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class SyntaxException extends JhethiaException{ 7 | 8 | public SyntaxException(String problem, String solution) { 9 | super(problem, solution); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Exceptions/ExecutionException.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Exceptions; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ExecutionException extends JhethiaException{ 7 | 8 | public ExecutionException(String problem, String solution) { 9 | super(problem, solution); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Exceptions/OperationException.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Exceptions; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class OperationException extends JhethiaException{ 7 | 8 | public OperationException(String problem, String solution) { 9 | super(problem, solution); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/FunctionStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class FunctionStatement extends CompositeStatement { 7 | public FunctionStatement(Integer rowNumber, String blockName) { 8 | super(rowNumber, blockName); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Exceptions/JhethiaException.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Exceptions; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class JhethiaException extends RuntimeException{ 7 | private String solution; 8 | public JhethiaException (String problem, String solution){ 9 | super(problem); 10 | this.solution = solution; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/Statement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | @RequiredArgsConstructor 7 | @Getter 8 | public abstract class Statement { 9 | private final Integer rowNumber; 10 | private final String blockName; 11 | 12 | public abstract void execute(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/ClassStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class ClassStatement extends CompositeStatement { 7 | private final Integer rowNumber; 8 | 9 | public ClassStatement(Integer rowNumber, String blockName) { 10 | super(rowNumber, blockName); 11 | this.rowNumber = rowNumber; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/definition/Definition.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context.definition; 2 | 3 | /** 4 | * Interface to specify structures supported by toy-language 5 | *

6 | * 7 | * @see ClassDefinition 8 | * @see FunctionDefinition 9 | */ 10 | public interface Definition { 11 | /** 12 | * Contains nested structures declared in this definition 13 | */ 14 | DefinitionScope getDefinitionScope(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/NumericValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | public class NumericValue extends ComparableValue { 4 | public NumericValue(Double value) { 5 | super(value); 6 | } 7 | 8 | @Override 9 | public String toString() { 10 | if ((getValue() % 1) == 0) 11 | return String.valueOf(getValue().intValue()); 12 | return super.toString(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/UnaryOperatorExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | import org.prakarshs.Syntax.Expressions.Expression; 7 | 8 | @RequiredArgsConstructor 9 | @Getter 10 | @ToString 11 | public abstract class UnaryOperatorExpression implements OperatorExpression { 12 | private final Expression value; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/Loops/NextStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements.Loops; 2 | 3 | import org.prakarshs.Syntax.Statements.Statement; 4 | import org.prakarshs.Context.NextContext; 5 | 6 | public class NextStatement extends Statement { 7 | public NextStatement(Integer rowNumber, String blockName) { 8 | super(rowNumber, blockName); 9 | } 10 | 11 | @Override 12 | public void execute() { 13 | NextContext.getScope().invoke(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/Loops/BreakStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements.Loops; 2 | 3 | import org.prakarshs.Context.BreakContext; 4 | import org.prakarshs.Syntax.Statements.Statement; 5 | 6 | public class BreakStatement extends Statement { 7 | public BreakStatement(Integer rowNumber, String blockName) { 8 | super(rowNumber, blockName); 9 | } 10 | 11 | @Override 12 | public void execute() { 13 | BreakContext.getScope().invoke(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/BinaryOperatorExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | import org.prakarshs.Syntax.Expressions.Expression; 7 | 8 | @RequiredArgsConstructor 9 | @Getter 10 | @ToString 11 | public abstract class BinaryOperatorExpression implements OperatorExpression { 12 | private final Expression left; 13 | private final Expression right; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/NextScope.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * Scope for the loop block defining if the next statement invoked 7 | *

8 | * 9 | * @see NextContext 10 | */ 11 | @Getter 12 | public class NextScope { 13 | private boolean invoked; 14 | 15 | /** 16 | * Notify the loop block about invoking the next statement 17 | */ 18 | public void invoke() { 19 | this.invoked = true; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/NullValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | public class NullValue> extends ComparableValue { 4 | 5 | public static final NullValue NULL_INSTANCE = new NullValue<>(null); 6 | 7 | public NullValue(T value) { 8 | super(value); 9 | } 10 | 11 | @Override 12 | public T getValue() { 13 | //noinspection unchecked 14 | return (T) this; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return "nill batte sannata"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Constants/ErrorConstants.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Constants; 2 | 3 | public class ErrorConstants { 4 | public static final String SYNTAX_GALAT_HAI = "Aye Nonsense Saatvi Fail !! Syntax Galat Hai!"; 5 | public static final String OPERATION_IMPOSSIBLE = "Arre Chalu Ji ! Pandey Ji ! Ye Operation Impowshibal Hai !"; 6 | public static final String EXECUTION_IMPOSSIBLE = "Aye Pagal Aurat ! Ye Execute Karna Impowshibal Hai !"; 7 | public static final String DIVISION_BY_ZERO = "Aye Dobiii ! Zero Se Divide Kar Rahi Hai Queen Victoria ?!"; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ClassInstanceOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Syntax.Expressions.Expression; 4 | import org.prakarshs.Syntax.Values.Value; 5 | 6 | public class ClassInstanceOperator extends UnaryOperatorExpression { 7 | public ClassInstanceOperator(Expression value) { 8 | super(value); 9 | } 10 | 11 | @Override 12 | public Value evaluate() { 13 | return getValue().evaluate(); // will return toString() value 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Tokens/Token.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Tokens; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | import lombok.ToString; 6 | 7 | /** 8 | * Token (lexeme) details 9 | */ 10 | @Builder 11 | @Getter 12 | @ToString 13 | public class Token { 14 | /** 15 | * Type of the token 16 | */ 17 | private final TokenType type; 18 | /** 19 | * Value of the token 20 | */ 21 | private final String value; 22 | /** 23 | * Row number where the token is defined 24 | */ 25 | private final Integer rowNumber; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/test/resources/binary_search.jhethia: -------------------------------------------------------------------------------- 1 | kaam binary_search [ arr, n, lo, hi, key ] 2 | agar hi >= lo 3 | mid = (hi + lo) // 2 4 | agar arr{mid} < key 5 | bhejo binary_search [ arr, n, mid + 1, hi, key ] 6 | yatoh arr{mid} > key 7 | bhejo binary_search [ arr, n, lo, mid - 1, key ] 8 | warna 9 | bhejo mid 10 | khatam 11 | warna 12 | bhejo -1 13 | khatam 14 | bhejo 15 | khatam 16 | 17 | arr = {10, 20, 30, 50, 60, 80, 110, 130, 140, 170} 18 | n = 10 19 | 20 | dekhiye_baapuji binary_search [ arr, n, 0, n - 1, 110 ] 21 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/ArrayExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | import org.prakarshs.Syntax.Values.ArrayValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | import java.util.List; 10 | 11 | @RequiredArgsConstructor 12 | @Getter 13 | @ToString 14 | public class ArrayExpression implements Expression { 15 | private final List values; 16 | 17 | @Override 18 | public Value evaluate() { 19 | return new ArrayValue(this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/BreakScope.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Syntax.Statements.Loops.BreakStatement; 5 | 6 | /** 7 | * Scope for the loop block defining if the break statement invoked 8 | *

9 | * 10 | * @see BreakContext 11 | * @see BreakStatement 12 | */ 13 | @Getter 14 | public class BreakScope { 15 | private boolean invoked; 16 | 17 | /** 18 | * Notify the loop block about invoking the break statement 19 | */ 20 | public void invoke() { 21 | this.invoked = true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/JhethiaRun.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs; 2 | 3 | import java.nio.file.FileSystems; 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | 7 | public class JhethiaRun { 8 | public static void main(String[] args) { 9 | Path sourceFilePath = FileSystems.getDefault().getPath(args[0]); 10 | System.out.println("** Jai Jinendra ! Nashta Kar Ke Jaana ! **"); 11 | if (Files.exists(sourceFilePath)) { 12 | new Jhethia().execute(sourceFilePath); 13 | } 14 | else { 15 | System.out.println("Cannot resolve args[0] [" + sourceFilePath + "] as a valid file path."); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/ThisValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | import org.prakarshs.Context.ClassInstanceContext; 4 | 5 | public class ThisValue extends Value { 6 | 7 | public static final ThisValue THIS_INSTANCE = new ThisValue(); 8 | 9 | public ThisValue() { 10 | super(null); 11 | } 12 | 13 | @Override 14 | public ClassValue getValue() { 15 | return ClassInstanceContext.getValue(); 16 | } 17 | 18 | @Override 19 | public Value evaluate() { 20 | return getValue(); 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return getValue().toString(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/ExpressionStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | 7 | @Getter 8 | public class ExpressionStatement extends Statement { 9 | private final Expression expression; 10 | 11 | public ExpressionStatement(Integer rowNumber, String blockName, Expression expression) { 12 | super(rowNumber, blockName); 13 | this.expression = expression; 14 | } 15 | 16 | @Override 17 | public void execute() { 18 | expression.evaluate(); 19 | ExceptionContext.addTracedStatement(this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/ReturnScope.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Syntax.Values.Value; 5 | import org.prakarshs.Syntax.Statements.CompositeStatement; 6 | 7 | /** 8 | * Scope for the {@link CompositeStatement} defining if the return statement invoked 9 | *

10 | * 11 | * @see BreakContext 12 | */ 13 | @Getter 14 | public class ReturnScope { 15 | private boolean invoked; 16 | private Value result; 17 | 18 | /** 19 | * Notify current scope that return statement invoked 20 | */ 21 | public void invoke(Value result) { 22 | this.invoked = true; 23 | this.result = result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/TextValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | public class TextValue extends ComparableValue { 4 | public TextValue(String value) { 5 | super(value); 6 | } 7 | 8 | public Value getValue(int index) { 9 | if (getValue().length() > index) 10 | return new TextValue(getValue().substring(index, index + 1)); 11 | return NullValue.NULL_INSTANCE; 12 | } 13 | 14 | public void setValue(int index, Value value) { 15 | if (getValue().length() > index) { 16 | String val = getValue(); 17 | super.setValue(val.substring(0, index) + value.toString() + val.substring(index)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /target/test-classes/hello_world.jhethia: -------------------------------------------------------------------------------- 1 | dhancha Person 2 | yeh_lo name 3 | yeh_lo experience 4 | yeh_lo is_developer 5 | khatam 6 | 7 | lijiye_baapuji your_name 8 | lijiye_baapuji your_experience_in_years 9 | lijiye_baapuji do_you_like_programming 10 | 11 | person = naya Person [your_name your_experience_in_years do_you_like_programming] 12 | dekhiye_baapuji person 13 | 14 | agar person ka is_developer toh 15 | 16 | person_name = person ka name 17 | dekhiye_baapuji "kaise ho " + person_name + "!" 18 | 19 | experience = person ka experience 20 | 21 | agar experience > 0 toh 22 | started_in = 2024 - experience 23 | dekhiye_baapuji "you had started your career in " + started_in 24 | khatam 25 | 26 | khatam -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/definition/ClassDetails.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context.definition; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import org.prakarshs.Parser.StatementParser; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Details of a class 12 | *

13 | * 14 | * @see ClassDefinition 15 | * @see StatementParser#readClassDetails() 16 | */ 17 | @RequiredArgsConstructor 18 | @Getter 19 | @EqualsAndHashCode(onlyExplicitlyIncluded = true) 20 | public class ClassDetails { 21 | /** 22 | * Class's name 23 | */ 24 | @EqualsAndHashCode.Include 25 | private final String name; 26 | /** 27 | * Names of the constructor properties 28 | */ 29 | private final List properties; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/NextContext.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import org.prakarshs.Syntax.Statements.Loops.AbstractLoopStatement; 4 | import org.prakarshs.Syntax.Statements.Loops.NextStatement; 5 | 6 | /** 7 | * Associates a given {@link NextScope} with a loop block 8 | *

9 | * 10 | * @see AbstractLoopStatement 11 | * @see NextStatement 12 | */ 13 | public class NextContext { 14 | private static NextScope scope = new NextScope(); 15 | 16 | /** 17 | * Get current {@link NextScope} 18 | */ 19 | public static NextScope getScope() { 20 | return scope; 21 | } 22 | 23 | /** 24 | * Reset state of the {@link NextContext} on loop exit 25 | */ 26 | public static void reset() { 27 | NextContext.scope = new NextScope(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/VariableExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | import org.prakarshs.Context.MemoryContext; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | @RequiredArgsConstructor 10 | @Getter 11 | @ToString 12 | public class VariableExpression implements Expression, AssignExpression { 13 | private final String name; 14 | 15 | @Override 16 | public Value evaluate() { 17 | return MemoryContext.getScope().get(name); 18 | } 19 | 20 | @Override 21 | public Value assign(Value value) { 22 | if (value == null) return null; 23 | MemoryContext.getScope().set(name, value); 24 | return value; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/BreakContext.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import org.prakarshs.Syntax.Statements.Loops.AbstractLoopStatement; 4 | import org.prakarshs.Syntax.Statements.Loops.BreakStatement; 5 | 6 | /** 7 | * Associates a given {@link BreakScope} with a loop block 8 | *

9 | * 10 | * @see AbstractLoopStatement 11 | * @see BreakStatement 12 | */ 13 | public class BreakContext { 14 | private static BreakScope scope = new BreakScope(); 15 | 16 | /** 17 | * Get current {@link BreakScope} 18 | */ 19 | public static BreakScope getScope() { 20 | return scope; 21 | } 22 | 23 | /** 24 | * Reset state of the {@link BreakContext} on loop exit 25 | */ 26 | public static void reset() { 27 | BreakContext.scope = new BreakScope(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/PrintStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | @Getter 9 | public class PrintStatement extends Statement { 10 | private final Expression expression; 11 | 12 | public PrintStatement(Integer rowNumber, String blockName, Expression expression) { 13 | super(rowNumber, blockName); 14 | this.expression = expression; 15 | } 16 | 17 | @Override 18 | public void execute() { 19 | Value value = expression.evaluate(); 20 | if (value != null) { 21 | System.out.println(value); 22 | } 23 | ExceptionContext.addTracedStatement(this); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ArrayAppendOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Syntax.Expressions.Expression; 4 | import org.prakarshs.Syntax.Values.ArrayValue; 5 | import org.prakarshs.Syntax.Values.Value; 6 | 7 | public class ArrayAppendOperator extends BinaryOperatorExpression { 8 | public ArrayAppendOperator(Expression left, Expression right) { 9 | super(left, right); 10 | } 11 | 12 | @Override 13 | public Value evaluate() { 14 | Value left = getLeft().evaluate(); 15 | if (left == null) return null; 16 | Value right = getRight().evaluate(); 17 | if (right == null) return null; 18 | 19 | if (left instanceof ArrayValue) { 20 | ((ArrayValue) left).appendValue(right); 21 | } 22 | return left; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/resources/bubble_sort.jhethia: -------------------------------------------------------------------------------- 1 | kaam bubble_sort [ arr, n ] 2 | chai_piyo i in 0..n - 1 3 | chai_piyo j in 0..n - i - 1 4 | agar arr{j+1} < arr{j} 5 | temp = arr{j} 6 | arr{j} = arr{j + 1} 7 | arr{j + 1} = temp 8 | khatam 9 | biscuit_khao 10 | biscuit_khao 11 | khatam 12 | 13 | kaam is_sorted [ arr, n ] 14 | chai_piyo i in 0..n - 1 15 | agar arr{i} > arr{i+1} 16 | bhejo "galat_baat_hai" 17 | khatam 18 | biscuit_khao 19 | bhejo "sahi_baat_hai" 20 | khatam 21 | 22 | arr = {} 23 | arr_len = 20 24 | 25 | arr = {-1, 14, 12, 10, 8, 6, 4, 2, 0, 15, 13, 11, 9, 7, 5, 3, 1, -1, 14, 12} 26 | 27 | dekhiye_baapuji arr 28 | dekhiye_baapuji is_sorted [ arr, arr_len ] 29 | bubble_sort [ arr, arr_len ] 30 | dekhiye_baapuji "After sorting :" 31 | dekhiye_baapuji is_sorted [ arr, arr_len ] 32 | dekhiye_baapuji arr -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/ReturnStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Context.ReturnContext; 6 | import org.prakarshs.Syntax.Expressions.Expression; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | @Getter 10 | public class ReturnStatement extends Statement { 11 | private final Expression expression; 12 | 13 | public ReturnStatement(Integer rowNumber, String blockName, Expression expression) { 14 | super(rowNumber, blockName); 15 | this.expression = expression; 16 | } 17 | 18 | @Override 19 | public void execute() { 20 | Value result = expression.evaluate(); 21 | if (result != null) { 22 | ReturnContext.getScope().invoke(result); 23 | } 24 | ExceptionContext.addTracedStatement(this); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/Value.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | 7 | @Getter 8 | @EqualsAndHashCode(onlyExplicitlyIncluded = true) 9 | public class Value implements Expression { 10 | @EqualsAndHashCode.Include 11 | private T value; 12 | 13 | public Value(T v) { 14 | setValue(v); 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | if(value.toString().equals("true")) 20 | return "sahi baat hai !"; 21 | else if (value.toString().equals("false")) 22 | return "galat baat hai !"; 23 | 24 | return value.toString(); 25 | } 26 | 27 | public void setValue(T v) { 28 | this.value = v; 29 | } 30 | 31 | @Override 32 | public Value evaluate() { 33 | return this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/NotOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.LogicalValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | public class NotOperator extends UnaryOperatorExpression { 9 | public NotOperator(Expression value) { 10 | super(value); 11 | } 12 | 13 | @Override 14 | public Value evaluate() { 15 | Value value = getValue().evaluate(); 16 | if (value == null) return null; 17 | if (value instanceof LogicalValue) { 18 | return new LogicalValue(!(((LogicalValue) value).getValue())); 19 | } else { 20 | return ExceptionContext.raiseException(String.format("Unable to perform NOT operator for non logical value `%s`", value)); 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/ReturnContext.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import org.prakarshs.Syntax.Expressions.FunctionExpression; 4 | import org.prakarshs.Syntax.Statements.CompositeStatement; 5 | import org.prakarshs.Syntax.Statements.ReturnStatement; 6 | import org.prakarshs.Syntax.Statements.Loops.AbstractLoopStatement; 7 | 8 | /** 9 | * Associates a given {@link ReturnScope} with {@link CompositeStatement} 10 | *

11 | * 12 | * @see AbstractLoopStatement 13 | * @see ReturnStatement 14 | * @see FunctionExpression 15 | */ 16 | public class ReturnContext { 17 | private static ReturnScope scope = new ReturnScope(); 18 | 19 | /** 20 | * Get current {@link ReturnScope} 21 | */ 22 | public static ReturnScope getScope() { 23 | return scope; 24 | } 25 | 26 | /** 27 | * Reset state of the {@link ReturnContext} on block exit 28 | */ 29 | public static void reset() { 30 | ReturnContext.scope = new ReturnScope(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/Loops/WhileLoopStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements.Loops; 2 | 3 | import org.prakarshs.Syntax.Expressions.Expression; 4 | import org.prakarshs.Syntax.Values.LogicalValue; 5 | import org.prakarshs.Syntax.Values.Value; 6 | 7 | public class WhileLoopStatement extends AbstractLoopStatement { 8 | private final Expression hasNext; 9 | 10 | public WhileLoopStatement(Integer rowNumber, String blockName, Expression hasNext) { 11 | super(rowNumber, blockName); 12 | this.hasNext = hasNext; 13 | } 14 | 15 | @Override 16 | protected void init() { 17 | } 18 | 19 | @Override 20 | protected boolean hasNext() { 21 | Value value = hasNext.evaluate(); 22 | return value instanceof LogicalValue && ((LogicalValue) value).getValue(); 23 | } 24 | 25 | @Override 26 | protected void preIncrement() { 27 | } 28 | 29 | @Override 30 | protected void postIncrement() { 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/AssertStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Values.LogicalValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | @Getter 10 | public class AssertStatement extends Statement { 11 | private final Expression expression; 12 | 13 | public AssertStatement(Integer rowNumber, String blockName, Expression expression) { 14 | super(rowNumber, blockName); 15 | this.expression = expression; 16 | } 17 | 18 | @Override 19 | public void execute() { 20 | Value value = expression.evaluate(); 21 | if (value instanceof LogicalValue && !((LogicalValue) value).getValue()) { 22 | ExceptionContext.raiseException("Assert Karne Me Error Ho Gaya Mehta Saab!"); 23 | ExceptionContext.addTracedStatement(this); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/MemoryContext.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Associates a given {@link MemoryScope} with isolated block of code 7 | */ 8 | public class MemoryContext { 9 | private static final Stack scopes = new Stack<>(); 10 | 11 | /** 12 | * Get scope of the current block 13 | */ 14 | public static MemoryScope getScope() { 15 | return scopes.peek(); 16 | } 17 | 18 | /** 19 | * Create and set a new MemoryScope to enter a nested block 20 | */ 21 | public static MemoryScope newScope() { 22 | return new MemoryScope(scopes.isEmpty() ? null : scopes.peek()); 23 | } 24 | 25 | /** 26 | * Set an existing scope to enter any block 27 | */ 28 | public static void pushScope(MemoryScope scope) { 29 | scopes.push(scope); 30 | } 31 | 32 | /** 33 | * Terminate the current scope to exit block 34 | */ 35 | public static void endScope() { 36 | scopes.pop(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/definition/FunctionDefinition.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context.definition; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import org.prakarshs.Parser.StatementParser; 7 | import org.prakarshs.Syntax.Statements.FunctionStatement; 8 | import org.prakarshs.Tokens.Token; 9 | 10 | /** 11 | * Definition for a function 12 | *

13 | * 14 | * @see StatementParser#parseFunctionDefinition(Token) 15 | */ 16 | @RequiredArgsConstructor 17 | @Getter 18 | @EqualsAndHashCode(onlyExplicitlyIncluded = true) 19 | public class FunctionDefinition implements Definition { 20 | /** 21 | * Details for a function 22 | */ 23 | @EqualsAndHashCode.Include 24 | private final FunctionDetails details; 25 | /** 26 | * Statement(s) defined in the function body 27 | */ 28 | private final FunctionStatement statement; 29 | /** 30 | * Contains nested classes and functions defined in this function 31 | */ 32 | private final DefinitionScope definitionScope; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/AssignmentOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.AssignExpression; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | public class AssignmentOperator extends BinaryOperatorExpression { 9 | public AssignmentOperator(Expression left, Expression right) { 10 | super(left, right); 11 | } 12 | 13 | @Override 14 | public Value evaluate() { 15 | Value left = getLeft().evaluate(); 16 | if (left == null) return null; 17 | Value right = getRight().evaluate(); 18 | if (right == null) return null; 19 | 20 | if (getLeft() instanceof AssignExpression) { 21 | return ((AssignExpression) getLeft()).assign(right); 22 | } else { 23 | return ExceptionContext.raiseException(String.format("Shorey. Ashignment Nahi Ho Payega. `%s``", getLeft())); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Tokens/TokenType.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Tokens; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.prakarshs.Parser.LexicalParser; 6 | 7 | @RequiredArgsConstructor 8 | @Getter 9 | public enum TokenType { 10 | 11 | Comment("\\#.*"), 12 | 13 | LineBreak("[\\n\\r]"), 14 | 15 | Whitespace("[\\s\\t]"), 16 | 17 | Keyword("(agar|yatoh|warna|khatam|dekhiye_baapuji|lijiye_baapuji|kilass|kaam|bhejo|chai_piyo|biscuit_khao|in|by|break|agla|assert|raise|ishtart|rescue|ensure)(?=\\s|$)(?!_)"), 18 | 19 | GroupDivider("(\\[|\\]|\\,|\\{|}|\\.{2}|(\\:(?!\\:)))"), 20 | 21 | Logical("(sahi_baat_hai|galat_baat_hai)(?=\\s|$)(?!_)"), 22 | 23 | Numeric("([-]?(?=[.]?[0-9])[0-9]*(?![.]{2})[.]?[0-9]*)"), 24 | 25 | Null("(null)(?=,|\\s|$)(?!_)"), 26 | 27 | This("(this)(?=,|\\s|$)(?!_)"), 28 | 29 | Text("\"([^\"]*)\""), 30 | 31 | Operator("(\\+|-|\\*{1,2}|/{1,2}|%|>=?|<=|<{1,2}|={1,2}|!=|!|ka\\s+naya|ka|\\(|\\)|(naya|aur|ya|as|is)(?=\\s|$)(?!_))"), 32 | 33 | Variable("[a-zA-Z_]+[a-zA-Z0-9_]*"); 34 | 35 | private final String regex; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ModuloOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.NumericValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | public class ModuloOperator extends BinaryOperatorExpression { 9 | public ModuloOperator(Expression left, Expression right) { 10 | super(left, right); 11 | } 12 | 13 | @Override 14 | public Value evaluate() { 15 | Value left = getLeft().evaluate(); 16 | if (left == null) return null; 17 | Value right = getRight().evaluate(); 18 | if (right == null) return null; 19 | if (left instanceof NumericValue && right instanceof NumericValue) { 20 | return new NumericValue(((NumericValue) left).getValue() % ((NumericValue) right).getValue()); 21 | } else { 22 | return ExceptionContext.raiseException(String.format("Unable to perform modulo for non numeric values `%s` and `%s`", left, right)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/RaiseExceptionStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Values.NullValue; 7 | import org.prakarshs.Syntax.Values.TextValue; 8 | import org.prakarshs.Syntax.Values.Value; 9 | 10 | @Getter 11 | public class RaiseExceptionStatement extends Statement { 12 | private final Expression expression; 13 | 14 | public RaiseExceptionStatement(Integer rowNumber, String blockName, Expression expression) { 15 | super(rowNumber, blockName); 16 | this.expression = expression; 17 | } 18 | 19 | @Override 20 | public void execute() { 21 | Value value = expression.evaluate(); 22 | if (value != null) { 23 | if (value == NullValue.NULL_INSTANCE) { 24 | value = new TextValue("Khaali(Null) Exception Hai Daya!"); 25 | } 26 | ExceptionContext.raiseException(value); 27 | } 28 | ExceptionContext.addTracedStatement(this); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/LogicalOrOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.LogicalValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | public class LogicalOrOperator extends BinaryOperatorExpression { 9 | public LogicalOrOperator(Expression left, Expression right) { 10 | super(left, right); 11 | } 12 | 13 | @Override 14 | public Value evaluate() { 15 | Value left = getLeft().evaluate(); 16 | if (left == null) return null; 17 | Value right = getRight().evaluate(); 18 | if (right == null) return null; 19 | if (left instanceof LogicalValue && right instanceof LogicalValue) { 20 | return new LogicalValue(((LogicalValue) left).getValue() || ((LogicalValue) right).getValue()); 21 | } else { 22 | return ExceptionContext.raiseException(String.format("Unable to perform OR operator for non logical values `%s`, '%s'", left, right)); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jhethia : Where Fafda Meets Code 2 |

3 | jhethia 4 |

5 | 6 | ## What Is Jhethia? 7 | Jhethia is a fun programming language modeled in Java, spiced up with the hilarious antics of Jhethalal. Its syntax somewhat mixes Rust and Python, promising a coding experience full of laughs and fun! Jhethia allows users to perform a wide range of basic operations typical of any programming language, all while injecting a dose of fun into the process. 8 | 9 | Know More [✨Here✨](https://prakarshs.github.io/JhethiaWeb/) 10 | 11 | ### Run this program 12 | - Firstly, Clone the repository in your system. 13 | - Secondly, Compile and package the program into a uber jar, go to the ./target folder and then run the following command 14 | ``` 15 | java -cp Jhethia.jar org.prakarshs.JhethiaRun src/test/resources/hello_world.jhethia 16 | ``` 17 | >You can add your own .(dot)jhethia files and run the code from the test/resources/{your_file} location 18 | 19 | 🙏🏻 Jai Jinendra 🙏🏻 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/LogicalAndOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.LogicalValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | public class LogicalAndOperator extends BinaryOperatorExpression { 9 | public LogicalAndOperator(Expression left, Expression right) { 10 | super(left, right); 11 | } 12 | 13 | @Override 14 | public Value evaluate() { 15 | Value left = getLeft().evaluate(); 16 | if (left == null) return null; 17 | Value right = getRight().evaluate(); 18 | if (right == null) return null; 19 | if (left instanceof LogicalValue && right instanceof LogicalValue) { 20 | return new LogicalValue(((LogicalValue) left).getValue() && ((LogicalValue) right).getValue()); 21 | } else { 22 | return ExceptionContext.raiseException(String.format("Unable to perform AND operator for non logical values `%s`, '%s'", left, right)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/definition/FunctionDetails.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context.definition; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | import java.util.List; 7 | import java.util.Objects; 8 | 9 | /** 10 | * Details for a function 11 | *

12 | * 13 | * @see FunctionDefinition 14 | */ 15 | @RequiredArgsConstructor 16 | @Getter 17 | public class FunctionDetails { 18 | /** 19 | * Function's name 20 | */ 21 | private final String name; 22 | /** 23 | * Names of the function arguments 24 | */ 25 | private final List arguments; 26 | 27 | /** 28 | * Compare function by its name and number of arguments 29 | */ 30 | @Override 31 | public boolean equals(Object o) { 32 | if (this == o) return true; 33 | if (o == null || getClass() != o.getClass()) return false; 34 | FunctionDetails that = (FunctionDetails) o; 35 | return Objects.equals(name, that.name) && arguments.size() == that.arguments.size(); 36 | } 37 | 38 | @Override 39 | public int hashCode() { 40 | return Objects.hash(name, arguments.size()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/DivisionOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.NumericValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | public class DivisionOperator extends BinaryOperatorExpression { 9 | public DivisionOperator(Expression left, Expression right) { 10 | super(left, right); 11 | } 12 | 13 | @Override 14 | public Value evaluate() { 15 | Value left = getLeft().evaluate(); 16 | if (left == null) return null; 17 | Value right = getRight().evaluate(); 18 | if (right == null) return null; 19 | if (left instanceof NumericValue && right instanceof NumericValue) { 20 | return new NumericValue(((NumericValue) left).getValue() / ((NumericValue) right).getValue()); 21 | } else { 22 | return ExceptionContext.raiseException(String.format("Do Non Numeric Values Ko Kaise Divide Karu? Chalu Ji ! Pandey Ji ! ( `%s` and `%s` )", left, right)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ExponentiationOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.NumericValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | 8 | public class ExponentiationOperator extends BinaryOperatorExpression { 9 | public ExponentiationOperator(Expression left, Expression right) { 10 | super(left, right); 11 | } 12 | 13 | @Override 14 | public Value evaluate() { 15 | Value left = getLeft().evaluate(); 16 | if (left == null) return null; 17 | Value right = getRight().evaluate(); 18 | if (right == null) return null; 19 | if (left instanceof NumericValue && right instanceof NumericValue) { 20 | return new NumericValue(Math.pow(((NumericValue) left).getValue(), ((NumericValue) right).getValue())); 21 | } else { 22 | return ExceptionContext.raiseException(String.format("Exponentiation Non Numeric Values Pe Nahi Ho Payega`%s` and `%s`", left, right)); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/definition/ClassDefinition.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context.definition; 2 | 3 | import lombok.EqualsAndHashCode; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | import org.prakarshs.Parser.StatementParser; 7 | import org.prakarshs.Syntax.Statements.ClassStatement; 8 | import org.prakarshs.Tokens.Token; 9 | 10 | import java.util.Set; 11 | 12 | /** 13 | * Definition for a class 14 | *

15 | * 16 | * @see StatementParser#parseClassDefinition(Token) 17 | */ 18 | @RequiredArgsConstructor 19 | @Getter 20 | @EqualsAndHashCode(onlyExplicitlyIncluded = true) 21 | public class ClassDefinition implements Definition { 22 | /** 23 | * Details for a class 24 | */ 25 | @EqualsAndHashCode.Include 26 | private final ClassDetails classDetails; 27 | /** 28 | * Details of the inherited (super) classes 29 | */ 30 | private final Set baseTypes; 31 | /** 32 | * Constructor statement 33 | */ 34 | private final ClassStatement statement; 35 | /** 36 | * Contains nested classes and functions defined in this class 37 | */ 38 | private final DefinitionScope definitionScope; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/definition/DefinitionContext.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context.definition; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Associates a given {@link DefinitionScope} with isolated block of code 7 | *

8 | * 9 | * @see DefinitionScope 10 | * @see ClassDefinition 11 | * @see FunctionDefinition 12 | */ 13 | public class DefinitionContext { 14 | private final static Stack scopes = new Stack<>(); 15 | 16 | /** 17 | * Get scope of the current block 18 | */ 19 | public static DefinitionScope getScope() { 20 | return scopes.peek(); 21 | } 22 | 23 | /** 24 | * Create and set a new DefinitionScope to enter a nested block 25 | */ 26 | public static DefinitionScope newScope() { 27 | return new DefinitionScope(scopes.isEmpty() ? null : scopes.peek()); 28 | } 29 | 30 | /** 31 | * Set an existing scope to enter any block 32 | */ 33 | public static void pushScope(DefinitionScope scope) { 34 | scopes.push(scope); 35 | } 36 | 37 | /** 38 | * Terminate the current scope to exit block 39 | */ 40 | public static void endScope() { 41 | scopes.pop(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/CompositeStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Context.ReturnContext; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | @Getter 11 | public class CompositeStatement extends Statement { 12 | private final List statements2Execute = new ArrayList<>(); 13 | 14 | public CompositeStatement(Integer rowNumber, String blockName) { 15 | super(rowNumber, blockName); 16 | } 17 | 18 | public void addStatement(Statement statement) { 19 | if (statement != null) 20 | statements2Execute.add(statement); 21 | } 22 | 23 | @Override 24 | public void execute() { 25 | for (Statement statement : statements2Execute) { 26 | statement.execute(); 27 | 28 | // stop the execution in case Exception occurred 29 | if (ExceptionContext.isRaised()) 30 | return; 31 | 32 | //stop the execution in case ReturnStatement is invoked 33 | if (ReturnContext.getScope().isInvoked()) 34 | return; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/EqualsOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Syntax.Expressions.Expression; 4 | import org.prakarshs.Syntax.Values.LogicalValue; 5 | import org.prakarshs.Syntax.Values.Value; 6 | import org.prakarshs.Syntax.Values.NullValue; 7 | 8 | import java.util.Objects; 9 | 10 | public class EqualsOperator extends BinaryOperatorExpression { 11 | public EqualsOperator(Expression left, Expression right) { 12 | super(left, right); 13 | } 14 | 15 | @Override 16 | public Value evaluate() { 17 | Value left = getLeft().evaluate(); 18 | if (left == null) return null; 19 | Value right = getRight().evaluate(); 20 | if (right == null) return null; 21 | boolean result; 22 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 23 | result = left == right; 24 | } else if (Objects.equals(left.getClass(), right.getClass())) { 25 | result = left.getValue().equals(right.getValue()); 26 | } else { 27 | result = left.toString().equals(right.toString()); 28 | } 29 | return new LogicalValue(result); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ClassInstanceOfOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Expressions.VariableExpression; 6 | import org.prakarshs.Syntax.Values.ClassValue; 7 | import org.prakarshs.Syntax.Values.LogicalValue; 8 | import org.prakarshs.Syntax.Values.Value; 9 | 10 | public class ClassInstanceOfOperator extends BinaryOperatorExpression { 11 | public ClassInstanceOfOperator(Expression left, Expression right) { 12 | super(left, right); 13 | } 14 | 15 | @Override 16 | public Value evaluate() { 17 | Value left = getLeft().evaluate(); 18 | if (left == null) return null; 19 | if (left instanceof ClassValue && getRight() instanceof VariableExpression) { 20 | String classType = ((VariableExpression) getRight()).getName(); 21 | return new LogicalValue(((ClassValue) left).containsRelation(classType)); 22 | } else { 23 | return ExceptionContext.raiseException(String.format("`is` Operator Nahi Lagwa Paunga for operands `%s` and `%s`", left, getRight())); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/NotEqualsOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Syntax.Expressions.Expression; 4 | import org.prakarshs.Syntax.Values.LogicalValue; 5 | import org.prakarshs.Syntax.Values.Value; 6 | import org.prakarshs.Syntax.Values.NullValue; 7 | 8 | import java.util.Objects; 9 | 10 | public class NotEqualsOperator extends BinaryOperatorExpression { 11 | public NotEqualsOperator(Expression left, Expression right) { 12 | super(left, right); 13 | } 14 | 15 | @Override 16 | public Value evaluate() { 17 | Value left = getLeft().evaluate(); 18 | if (left == null) return null; 19 | Value right = getRight().evaluate(); 20 | if (right == null) return null; 21 | boolean result; 22 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 23 | result = left != right; 24 | } else if (Objects.equals(left.getClass(), right.getClass())) { 25 | result = !left.getValue().equals(right.getValue()); 26 | } else { 27 | result = !left.toString().equals(right.toString()); 28 | } 29 | return new LogicalValue(result); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/resources/calculator.jhethia: -------------------------------------------------------------------------------- 1 | kilass Add [x, y] 2 | kaam sum 3 | bhejo x + y 4 | khatam 5 | khatam 6 | 7 | kilass Mul [a, b] 8 | kaam mul 9 | bhejo a * b 10 | khatam 11 | khatam 12 | 13 | kilass Sub [a, b] 14 | kaam sub 15 | bhejo a - b 16 | khatam 17 | khatam 18 | 19 | kilass Div [m, n] 20 | kaam div 21 | bhejo m / n 22 | khatam 23 | khatam 24 | 25 | kilass Exp [m, n] 26 | kaam exp 27 | bhejo m ** n 28 | khatam 29 | khatam 30 | 31 | kilass Fib [ n ] 32 | kaam fib 33 | bhejo fib [ n ] 34 | khatam 35 | 36 | kaam fib [ n ] 37 | agar n < 2 38 | bhejo n 39 | khatam 40 | bhejo fib [ n - 1 ] + fib [ n - 2 ] 41 | khatam 42 | khatam 43 | 44 | kilass Calculator [p, q]: Add [p, q], Sub [q, p], 45 | Mul [p, q], Div [q, p], 46 | Exp [p, q], Fib [ q ] 47 | khatam 48 | 49 | calc = naya Calculator [2, 10] 50 | 51 | dekhiye_baapuji "Sum : " +calc ka sum [] 52 | dekhiye_baapuji "Substraction : " +calc ka sub [] 53 | dekhiye_baapuji "Multiplication : " +calc ka mul [] 54 | dekhiye_baapuji "Division : " +calc ka div [] 55 | dekhiye_baapuji "Exponent : " +calc ka exp [] 56 | dekhiye_baapuji "Fibonacci : " +calc ka fib [] -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/ClassInstanceContext.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import org.prakarshs.Syntax.Expressions.ExpressionReader; 4 | import org.prakarshs.Syntax.Expressions.FunctionExpression; 5 | import org.prakarshs.Syntax.Values.ClassValue; 6 | import org.prakarshs.Syntax.Values.ThisValue; 7 | 8 | import java.util.Stack; 9 | 10 | /** 11 | * Associates a given {@link ClassValue} with this reference for the current block of code 12 | *

13 | * 14 | * @see ThisValue#getValue() 15 | * @see ExpressionReader 16 | * @see FunctionExpression 17 | */ 18 | public class ClassInstanceContext { 19 | private static final Stack values = new Stack<>(); 20 | 21 | /** 22 | * Get current this reference 23 | */ 24 | public static ClassValue getValue() { 25 | return values.peek(); 26 | } 27 | 28 | /** 29 | * Push new this reference when entering a class's constructor or invoking a class's function 30 | */ 31 | public static void pushValue(ClassValue instance) { 32 | values.push(instance); 33 | } 34 | 35 | /** 36 | * Pop this reference on block exit 37 | */ 38 | public static void popValue() { 39 | values.pop(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Jhethia.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs; 2 | 3 | import lombok.SneakyThrows; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Context.MemoryContext; 6 | import org.prakarshs.Context.definition.DefinitionContext; 7 | import org.prakarshs.Syntax.Statements.CompositeStatement; 8 | import org.prakarshs.Parser.LexicalParser; 9 | import org.prakarshs.Parser.StatementParser; 10 | import org.prakarshs.Tokens.Token; 11 | 12 | import java.nio.file.Files; 13 | import java.nio.file.Path; 14 | import java.util.List; 15 | 16 | public class Jhethia { 17 | 18 | @SneakyThrows 19 | public void execute(Path path) { 20 | String sourceCode = Files.readString(path); 21 | List tokens = LexicalParser.parse(sourceCode); 22 | 23 | DefinitionContext.pushScope(DefinitionContext.newScope()); 24 | MemoryContext.pushScope(MemoryContext.newScope()); 25 | try { 26 | CompositeStatement statement = new CompositeStatement(null, path.getFileName().toString()); 27 | StatementParser.parse(tokens, statement); 28 | statement.execute(); 29 | } finally { 30 | DefinitionContext.endScope(); 31 | MemoryContext.endScope(); 32 | 33 | if (ExceptionContext.isRaised()) { 34 | ExceptionContext.printStackTrace(); 35 | } 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/SubtractionOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.NumericValue; 6 | import org.prakarshs.Syntax.Values.TextValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | import org.prakarshs.Syntax.Values.NullValue; 9 | 10 | public class SubtractionOperator extends BinaryOperatorExpression { 11 | public SubtractionOperator(Expression left, Expression right) { 12 | super(left, right); 13 | } 14 | 15 | @Override 16 | public Value evaluate() { 17 | Value left = getLeft().evaluate(); 18 | if (left == null) return null; 19 | Value right = getRight().evaluate(); 20 | if (right == null) return null; 21 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 22 | return ExceptionContext.raiseException(String.format("Unable to perform subtraction for NULL values `%s`, '%s'", left, right)); 23 | } else if (left instanceof NumericValue && right instanceof NumericValue) { 24 | return new NumericValue(((NumericValue) left).getValue() - ((NumericValue) right).getValue()); 25 | } else { 26 | return new TextValue(left.toString().replaceAll(right.toString(), "")); 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ClassCastOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.definition.ClassDetails; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Expressions.VariableExpression; 6 | import org.prakarshs.Syntax.Values.ClassValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | /** 10 | * Cast a class instance from one type to other 11 | */ 12 | public class ClassCastOperator extends BinaryOperatorExpression { 13 | public ClassCastOperator(Expression left, Expression right) { 14 | super(left, right); 15 | } 16 | 17 | @Override 18 | public Value evaluate() { 19 | Value left = getLeft().evaluate(); 20 | if (left == null) return null; 21 | 22 | // evaluate expressions 23 | ClassValue classInstance = (ClassValue) left; 24 | String typeToCastName = ((VariableExpression) getRight()).getName(); 25 | 26 | // retrieve class details 27 | ClassDetails classDetails = classInstance.getValue().getClassDetails(); 28 | 29 | // check if the type to cast is different from original 30 | if (classDetails.getName().equals(typeToCastName)) { 31 | return classInstance; 32 | } else { 33 | // retrieve ClassValue of other type 34 | return classInstance.getRelation(typeToCastName); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/FloorDivisionOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.NumericValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | import org.prakarshs.Syntax.Values.NullValue; 8 | 9 | public class FloorDivisionOperator extends BinaryOperatorExpression { 10 | public FloorDivisionOperator(Expression left, Expression right) { 11 | super(left, right); 12 | } 13 | 14 | @Override 15 | public Value evaluate() { 16 | Value left = getLeft().evaluate(); 17 | if (left == null) return null; 18 | Value right = getRight().evaluate(); 19 | if (right == null) return null; 20 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 21 | return ExceptionContext.raiseException(String.format("Unable to perform floor division for NULL values `%s`, '%s'", left, right)); 22 | } else if (left instanceof NumericValue && right instanceof NumericValue) { 23 | return new NumericValue(Math.floor(((NumericValue) left).getValue() / ((NumericValue) right).getValue())); 24 | } else { 25 | return ExceptionContext.raiseException(String.format("Do non numeric values Kaise Divide Hoga Baapuji? `%s` and `%s`", left, right)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/NestedClassInstanceOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.ClassExpression; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Values.ClassValue; 7 | import org.prakarshs.Syntax.Values.ThisValue; 8 | import org.prakarshs.Syntax.Values.Value; 9 | 10 | public class NestedClassInstanceOperator extends BinaryOperatorExpression { 11 | public NestedClassInstanceOperator(Expression left, Expression right) { 12 | super(left, right); 13 | } 14 | 15 | @Override 16 | public Value evaluate() { 17 | Value left = getLeft().evaluate(); 18 | if (left == null) return null; 19 | 20 | // access class's property via this instance 21 | // this :: new NestedClass [] 22 | if (left instanceof ThisValue) { 23 | left = ((ThisValue) left).getValue(); 24 | } 25 | 26 | if (left instanceof ClassValue && getRight() instanceof ClassExpression) { 27 | // instantiate nested class 28 | // new Class [] :: new NestedClass [] 29 | return ((ClassExpression) getRight()).evaluate((ClassValue) left); 30 | } else { 31 | return ExceptionContext.raiseException(String.format("Unable to access class's nested class `%s``", getRight())); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/LessThanOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.ComparableValue; 6 | import org.prakarshs.Syntax.Values.LogicalValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | import org.prakarshs.Syntax.Values.NullValue; 9 | 10 | import java.util.Objects; 11 | 12 | public class LessThanOperator extends BinaryOperatorExpression { 13 | public LessThanOperator(Expression left, Expression right) { 14 | super(left, right); 15 | } 16 | 17 | @Override 18 | public Value evaluate() { 19 | Value left = getLeft().evaluate(); 20 | if (left == null) return null; 21 | Value right = getRight().evaluate(); 22 | if (right == null) return null; 23 | boolean result; 24 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 25 | return ExceptionContext.raiseException(String.format("NULL Ko Less Than karegi Dobi??? Values : `%s`, '%s'", left, right)); 26 | } else if (Objects.equals(left.getClass(), right.getClass()) && left instanceof ComparableValue) { 27 | //noinspection unchecked,rawtypes 28 | result = ((Comparable) left.getValue()).compareTo(right.getValue()) < 0; 29 | } else { 30 | result = left.toString().compareTo(right.toString()) < 0; 31 | } 32 | return new LogicalValue(result); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/GreaterThanOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.ComparableValue; 6 | import org.prakarshs.Syntax.Values.LogicalValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | import org.prakarshs.Syntax.Values.NullValue; 9 | 10 | import java.util.Objects; 11 | 12 | public class GreaterThanOperator extends BinaryOperatorExpression { 13 | public GreaterThanOperator(Expression left, Expression right) { 14 | super(left, right); 15 | } 16 | 17 | @Override 18 | public Value evaluate() { 19 | Value left = getLeft().evaluate(); 20 | if (left == null) return null; 21 | Value right = getRight().evaluate(); 22 | if (right == null) return null; 23 | boolean result; 24 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 25 | return ExceptionContext.raiseException(String.format("Unable to perform greater than for NULL values `%s`, '%s'", left, right)); 26 | } else if (Objects.equals(left.getClass(), right.getClass()) && left instanceof ComparableValue) { 27 | //noinspection unchecked,rawtypes 28 | result = ((Comparable) left.getValue()).compareTo(right.getValue()) > 0; 29 | } else { 30 | result = left.toString().compareTo(right.toString()) > 0; 31 | } 32 | return new LogicalValue(result); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/LessThanOrEqualToOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.ComparableValue; 6 | import org.prakarshs.Syntax.Values.LogicalValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | import org.prakarshs.Syntax.Values.NullValue; 9 | 10 | import java.util.Objects; 11 | 12 | public class LessThanOrEqualToOperator extends BinaryOperatorExpression { 13 | public LessThanOrEqualToOperator(Expression left, Expression right) { 14 | super(left, right); 15 | } 16 | 17 | @Override 18 | public Value evaluate() { 19 | Value left = getLeft().evaluate(); 20 | if (left == null) return null; 21 | Value right = getRight().evaluate(); 22 | if (right == null) return null; 23 | boolean result; 24 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 25 | return ExceptionContext.raiseException(String.format("Unable to perform less than or equal to for NULL values `%s`, '%s'", left, right)); 26 | } else if (Objects.equals(left.getClass(), right.getClass()) && left instanceof ComparableValue) { 27 | //noinspection unchecked,rawtypes 28 | result = ((Comparable) left.getValue()).compareTo(right.getValue()) <= 0; 29 | } else { 30 | result = left.toString().compareTo(right.toString()) <= 0; 31 | } 32 | return new LogicalValue(result); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/GreaterThanOrEqualToOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.ComparableValue; 6 | import org.prakarshs.Syntax.Values.LogicalValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | import org.prakarshs.Syntax.Values.NullValue; 9 | 10 | import java.util.Objects; 11 | 12 | public class GreaterThanOrEqualToOperator extends BinaryOperatorExpression { 13 | public GreaterThanOrEqualToOperator(Expression left, Expression right) { 14 | super(left, right); 15 | } 16 | 17 | @Override 18 | public Value evaluate() { 19 | Value left = getLeft().evaluate(); 20 | if (left == null) return null; 21 | Value right = getRight().evaluate(); 22 | if (right == null) return null; 23 | boolean result; 24 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 25 | return ExceptionContext.raiseException(String.format("Unable to perform greater than or equal to for NULL values `%s`, '%s'", left, right)); 26 | } else if (Objects.equals(left.getClass(), right.getClass()) && left instanceof ComparableValue) { 27 | //noinspection unchecked,rawtypes 28 | result = ((Comparable) left.getValue()).compareTo(right.getValue()) >= 0; 29 | } else { 30 | result = left.toString().compareTo(right.toString()) >= 0; 31 | } 32 | return new LogicalValue(result); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/ConditionStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.MemoryContext; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Values.LogicalValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | 12 | @Getter 13 | public class ConditionStatement extends Statement { 14 | private final Map cases; 15 | 16 | public ConditionStatement(Integer rowNumber, String blockName) { 17 | super(rowNumber, blockName); 18 | //keep the cases order 19 | this.cases = new LinkedHashMap<>(); 20 | } 21 | 22 | public void addCase(Expression caseCondition, CompositeStatement caseStatement) { 23 | cases.put(caseCondition, caseStatement); 24 | } 25 | 26 | @Override 27 | public void execute() { 28 | for (Map.Entry entry : cases.entrySet()) { 29 | 30 | Expression condition = entry.getKey(); 31 | Value value = condition.evaluate(); 32 | if (value instanceof LogicalValue && ((LogicalValue) value).getValue()) { 33 | MemoryContext.pushScope(MemoryContext.newScope()); 34 | try { 35 | CompositeStatement statement = entry.getValue(); 36 | statement.execute(); 37 | } finally { 38 | MemoryContext.endScope(); 39 | } 40 | break; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/InputStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.MemoryContext; 5 | import org.prakarshs.Syntax.Values.LogicalValue; 6 | import org.prakarshs.Syntax.Values.NumericValue; 7 | import org.prakarshs.Syntax.Values.TextValue; 8 | import org.prakarshs.Syntax.Values.Value; 9 | import org.prakarshs.Tokens.TokenType; 10 | 11 | import java.util.function.Supplier; 12 | 13 | @Getter 14 | public class InputStatement extends Statement { 15 | private final String name; 16 | private final Supplier consoleSupplier; 17 | 18 | public InputStatement(Integer rowNumber, String blockName, String name, Supplier consoleSupplier) { 19 | super(rowNumber, blockName); 20 | this.name = name; 21 | this.consoleSupplier = consoleSupplier; 22 | } 23 | 24 | @Override 25 | public void execute() { 26 | System.out.printf("enter \"%s\" >>> ", name.replace("_", " ")); 27 | String line = consoleSupplier.get(); 28 | 29 | Value value=null; 30 | if (line.matches(TokenType.Numeric.getRegex())) { 31 | value = new NumericValue(Double.parseDouble(line)); 32 | } else if (line.matches("sahi_baat_hai|galat_baat_hai")) { 33 | if(line.equals("sahi_baat_hai")) 34 | value = new LogicalValue(true); 35 | else if (line.equals("galat_baat_hai")) 36 | value = new LogicalValue(false); 37 | } else { 38 | value = new TextValue(line); 39 | } 40 | 41 | MemoryContext.getScope().set(name, value); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/Loops/IterableLoopStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements.Loops; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Context.MemoryContext; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Expressions.VariableExpression; 7 | import org.prakarshs.Syntax.Values.IterableValue; 8 | import org.prakarshs.Syntax.Values.Value; 9 | 10 | import java.util.Iterator; 11 | 12 | public class IterableLoopStatement extends AbstractLoopStatement { 13 | private final VariableExpression variableExpression; 14 | private final Expression iterableExpression; 15 | 16 | private Iterator> iterator; 17 | 18 | public IterableLoopStatement(Integer rowNumber, String blockName, VariableExpression variableExpression, Expression iterableExpression) { 19 | super(rowNumber, blockName); 20 | this.variableExpression = variableExpression; 21 | this.iterableExpression = iterableExpression; 22 | } 23 | 24 | @Override 25 | protected void init() { 26 | Value value = iterableExpression.evaluate(); 27 | if (!(value instanceof IterableValue)) { 28 | ExceptionContext.raiseException(String.format("Ghum Nahi Pa Raha`%s`", value)); 29 | return; 30 | } 31 | this.iterator = ((IterableValue) value).iterator(); 32 | } 33 | 34 | @Override 35 | protected boolean hasNext() { 36 | return iterator.hasNext(); 37 | } 38 | 39 | @Override 40 | protected void preIncrement() { 41 | MemoryContext.getScope().set(variableExpression.getName(), iterator.next()); 42 | } 43 | 44 | @Override 45 | protected void postIncrement() { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/ArrayValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | import org.prakarshs.Syntax.Expressions.ArrayExpression; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | 6 | import java.util.HashSet; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | import static org.prakarshs.Syntax.Values.NullValue.NULL_INSTANCE; 12 | 13 | public class ArrayValue extends IterableValue>> { 14 | public ArrayValue(ArrayExpression expression) { 15 | this(expression.getValues() 16 | .stream() 17 | .map(Expression::evaluate) 18 | .collect(Collectors.toList())); 19 | } 20 | 21 | public ArrayValue(List> values) { 22 | super(values); 23 | } 24 | 25 | public Value getValue(int index) { 26 | if (getValue().size() > index) 27 | return getValue().get(index); 28 | return NULL_INSTANCE; 29 | } 30 | 31 | public void setValue(int index, Value value) { 32 | if (getValue().size() > index) 33 | getValue().set(index, value); 34 | } 35 | 36 | public void appendValue(Value value) { 37 | getValue().add(value); 38 | } 39 | 40 | @Override 41 | public boolean equals(Object o) { 42 | if (this == o) return true; 43 | if (o == null) return false; 44 | if (getClass() != o.getClass()) return false; 45 | //noinspection unchecked 46 | List> oValue = (List>) o; 47 | return new HashSet<>(getValue()).containsAll(oValue); 48 | } 49 | 50 | @Override 51 | public Iterator> iterator() { 52 | return getValue().iterator(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ArrayValueOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Syntax.Expressions.AssignExpression; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.ArrayValue; 6 | import org.prakarshs.Syntax.Values.TextValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | public class ArrayValueOperator extends BinaryOperatorExpression implements AssignExpression { 10 | public ArrayValueOperator(Expression left, Expression right) { 11 | super(left, right); 12 | } 13 | 14 | @Override 15 | public Value evaluate() { 16 | Value left = getLeft().evaluate(); 17 | if (left == null) return null; 18 | Value right = getRight().evaluate(); 19 | if (right == null) return null; 20 | 21 | if (left instanceof ArrayValue) { 22 | return ((ArrayValue) left).getValue(((Double) right.getValue()).intValue()); 23 | } 24 | if (left instanceof TextValue) { 25 | return ((TextValue) left).getValue(((Double) right.getValue()).intValue()); 26 | } 27 | return left; 28 | } 29 | 30 | @Override 31 | public Value assign(Value value) { 32 | Value left = getLeft().evaluate(); 33 | if (left == null) return null; 34 | Value right = getRight().evaluate(); 35 | if (right == null) return null; 36 | 37 | if (left instanceof ArrayValue) { 38 | ((ArrayValue) left).setValue(((Double) right.getValue()).intValue(), value); 39 | } 40 | if (left instanceof TextValue) { 41 | ((TextValue) left).setValue(((Double) right.getValue()).intValue(), value); 42 | } 43 | return left; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/MultiplicationOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Values.NumericValue; 6 | import org.prakarshs.Syntax.Values.TextValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | import org.prakarshs.Syntax.Values.NullValue; 9 | 10 | public class MultiplicationOperator extends BinaryOperatorExpression { 11 | public MultiplicationOperator(Expression left, Expression right) { 12 | super(left, right); 13 | } 14 | 15 | @Override 16 | public Value evaluate() { 17 | Value left = getLeft().evaluate(); 18 | if (left == null) return null; 19 | Value right = getRight().evaluate(); 20 | if (right == null) return null; 21 | if (left == NullValue.NULL_INSTANCE || right == NullValue.NULL_INSTANCE) { 22 | return ExceptionContext.raiseException(String.format("Unable to perform multiplication for NULL values `%s`, '%s'", left, right)); 23 | } else if (left instanceof NumericValue && right instanceof NumericValue) { 24 | return new NumericValue(((NumericValue) left).getValue() * ((NumericValue) right).getValue()); 25 | } else if (left instanceof NumericValue) { 26 | return new TextValue(right.toString().repeat(((NumericValue) left).getValue().intValue())); 27 | } else if (right instanceof NumericValue) { 28 | return new TextValue(left.toString().repeat(((NumericValue) right).getValue().intValue())); 29 | } else { 30 | return ExceptionContext.raiseException(String.format("Unable to multiply non numeric values `%s` and `%s`", left, right)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/ValueReference.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.ToString; 6 | import org.prakarshs.Syntax.Expressions.Expression; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | /** 10 | * Wrapper for the Value to keep the properties' relations between Base and Derived classes 11 | *

12 | *

{@code
13 |  * # Declare the Base class A
14 |  * class A [a_value]
15 |  * end
16 |  *
17 |  * # Declare the Derived class B that inherits class A and initializes its `a_value` property with the `b_value` parameter
18 |  * class B [b_value]: A [b_value]
19 |  * end
20 |  *
21 |  * # Create an instance of class B
22 |  * b = new B [ b_value ]
23 |  *
24 |  * # If we change the `b_value` property, the A class's property `a_value` should be updated as well
25 |  * b :: b_value = new_value
26 |  *
27 |  * # a_new_value should contain `new_value`
28 |  * a_new_value = b as A :: a_value
29 |  * }
30 | */ 31 | @Getter 32 | @Setter 33 | @ToString 34 | public class ValueReference implements Expression { 35 | private Value value; 36 | 37 | private ValueReference(Value value) { 38 | this.value = value; 39 | } 40 | 41 | /** 42 | * Evaluates Expression and creates ValueReference for it 43 | */ 44 | public static ValueReference instanceOf(Expression expression) { 45 | if (expression instanceof ValueReference) { 46 | // reuse variable 47 | return (ValueReference) expression; 48 | } else { 49 | Value value = expression.evaluate(); 50 | if (value == null) return null; 51 | return new ValueReference(value); 52 | } 53 | } 54 | 55 | @Override 56 | public Value evaluate() { 57 | return value; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/AdditionOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Syntax.Expressions.Expression; 4 | import org.prakarshs.Syntax.Values.ArrayValue; 5 | import org.prakarshs.Syntax.Values.NumericValue; 6 | import org.prakarshs.Syntax.Values.TextValue; 7 | import org.prakarshs.Syntax.Values.Value; 8 | 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | import java.util.stream.Stream; 12 | 13 | public class AdditionOperator extends BinaryOperatorExpression { 14 | public AdditionOperator(Expression left, Expression right) { 15 | super(left, right); 16 | } 17 | 18 | @Override 19 | public Value evaluate() { 20 | Value left = getLeft().evaluate(); 21 | if (left == null) return null; 22 | Value right = getRight().evaluate(); 23 | if (right == null) return null; 24 | if (left instanceof NumericValue && right instanceof NumericValue) { 25 | return new NumericValue(((NumericValue) left).getValue() + ((NumericValue) right).getValue()); 26 | } else if (left instanceof ArrayValue || right instanceof ArrayValue) { 27 | List> newArray; 28 | if (left instanceof ArrayValue && right instanceof ArrayValue) { 29 | newArray = Stream.concat(((ArrayValue) left).getValue().stream(), ((ArrayValue) right).getValue().stream()) 30 | .collect(Collectors.toList()); 31 | } else if (left instanceof ArrayValue) { 32 | newArray = Stream.concat(((ArrayValue) left).getValue().stream(), Stream.of(right)) 33 | .collect(Collectors.toList()); 34 | } else { 35 | newArray = Stream.concat(((ArrayValue) right).getValue().stream(), Stream.of(left)) 36 | .collect(Collectors.toList()); 37 | } 38 | return new ArrayValue(newArray); 39 | } else { 40 | return new TextValue(left.toString() + right.toString()); 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/Loops/ForLoopStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements.Loops; 2 | 3 | import org.prakarshs.Context.MemoryContext; 4 | import org.prakarshs.Syntax.Expressions.Expression; 5 | import org.prakarshs.Syntax.Expressions.VariableExpression; 6 | import org.prakarshs.Syntax.Expressions.Operators.AdditionOperator; 7 | import org.prakarshs.Syntax.Expressions.Operators.LessThanOperator; 8 | import org.prakarshs.Syntax.Values.LogicalValue; 9 | import org.prakarshs.Syntax.Values.NumericValue; 10 | import org.prakarshs.Syntax.Values.Value; 11 | 12 | public class ForLoopStatement extends AbstractLoopStatement { 13 | private final VariableExpression variable; 14 | private final Expression lowerBound; 15 | private final Expression uppedBound; 16 | private final Expression step; 17 | private static final Expression DEFAULT_STEP = new NumericValue(1.0); 18 | 19 | public ForLoopStatement(Integer rowNumber, String blockName, VariableExpression variable, Expression lowerBound, Expression uppedBound) { 20 | this(rowNumber, blockName, variable, lowerBound, uppedBound, DEFAULT_STEP); 21 | } 22 | 23 | public ForLoopStatement(Integer rowNumber, String blockName, VariableExpression variable, Expression lowerBound, Expression uppedBound, Expression step) { 24 | super(rowNumber, blockName); 25 | this.variable = variable; 26 | this.lowerBound = lowerBound; 27 | this.uppedBound = uppedBound; 28 | this.step = step; 29 | } 30 | 31 | @Override 32 | protected void init() { 33 | MemoryContext.getScope().set(variable.getName(), lowerBound.evaluate()); 34 | } 35 | 36 | @Override 37 | protected boolean hasNext() { 38 | LessThanOperator hasNext = new LessThanOperator(variable, uppedBound); 39 | Value value = hasNext.evaluate(); 40 | return value instanceof LogicalValue && ((LogicalValue) value).getValue(); 41 | } 42 | 43 | @Override 44 | protected void preIncrement() { 45 | } 46 | 47 | @Override 48 | protected void postIncrement() { 49 | AdditionOperator stepOperator = new AdditionOperator(variable, step); 50 | MemoryContext.getScope().set(variable.getName(), stepOperator.evaluate()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/Operator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | import java.util.Arrays; 7 | 8 | @RequiredArgsConstructor 9 | @Getter 10 | public enum Operator { 11 | Not("!", NotOperator.class, 7), 12 | ClassInstance("naya", ClassInstanceOperator.class, 7), 13 | NestedClassInstance("ka\\s+naya", NestedClassInstanceOperator.class, 7), 14 | ClassProperty("ka", ClassPropertyOperator.class, 7), 15 | ClassCast("as", ClassCastOperator.class, 7), 16 | ClassInstanceOf("is", ClassInstanceOfOperator.class, 7), 17 | 18 | ExponentiationOperator("\\*{2}", ExponentiationOperator.class, 6), 19 | Multiplication("\\*", MultiplicationOperator.class, 6), 20 | Division("/", DivisionOperator.class, 6), 21 | FloorDivision("//", FloorDivisionOperator.class, 6), 22 | Modulo("%", ModuloOperator.class, 6), 23 | 24 | Addition("\\+", AdditionOperator.class, 5), 25 | Subtraction("-", SubtractionOperator.class, 5), 26 | 27 | Equals("==", EqualsOperator.class, 4), 28 | NotEquals("!=", NotEqualsOperator.class, 4), 29 | LessThan("<", LessThanOperator.class, 4), 30 | LessThanOrEqualTo("<=", LessThanOrEqualToOperator.class, 4), 31 | GreaterThan(">", GreaterThanOperator.class, 4), 32 | GreaterThanOrEqualTo(">=", GreaterThanOrEqualToOperator.class, 4), 33 | 34 | LeftParen("\\(", 3), 35 | RightParen("\\)", 3), 36 | 37 | LogicalAnd("aur", LogicalAndOperator.class, 2), 38 | LogicalOr("ya", LogicalOrOperator.class, 1), 39 | 40 | ArrayAppend("<<", ArrayAppendOperator.class, 0), 41 | Assignment("=", AssignmentOperator.class, 0); 42 | 43 | private final String character; 44 | private final Class type; 45 | private final Integer precedence; 46 | 47 | Operator(String character, Integer precedence) { 48 | this(character, null, precedence); 49 | } 50 | 51 | public static Operator getType(String character) { 52 | return Arrays.stream(values()) 53 | .filter(t -> character.matches(t.getCharacter())) 54 | .findAny().orElse(null); 55 | } 56 | 57 | public boolean greaterThan(Operator o) { 58 | return getPrecedence().compareTo(o.getPrecedence()) >= 0; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Parser/LexicalParser.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Parser; 2 | 3 | import org.prakarshs.Constants.ErrorConstants; 4 | import org.prakarshs.Exceptions.SyntaxException; 5 | import org.prakarshs.Tokens.Token; 6 | import org.prakarshs.Tokens.TokenType; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | public class LexicalParser { 14 | 15 | private final List tokens; 16 | 17 | private final String source; 18 | 19 | private int rowNumber; 20 | 21 | public static List parse(String sourceCode) { 22 | LexicalParser parser = new LexicalParser(sourceCode); 23 | parser.parse(); 24 | return parser.tokens; 25 | } 26 | 27 | private LexicalParser(String source) { 28 | this.source = source; 29 | this.tokens = new ArrayList<>(); 30 | this.rowNumber = 1; 31 | } 32 | 33 | private void parse() { 34 | int position = 0; 35 | while (position < source.length()) { 36 | position += nextToken(position); 37 | } 38 | } 39 | 40 | private int nextToken(int position) { 41 | String nextToken = source.substring(position); 42 | 43 | for (TokenType tokenType : TokenType.values()) { 44 | Pattern pattern = Pattern.compile("^" + tokenType.getRegex()); 45 | Matcher matcher = pattern.matcher(nextToken); 46 | if (matcher.find()) { 47 | if (tokenType != TokenType.Whitespace) { 48 | String value = matcher.groupCount() > 0 ? matcher.group(1) : matcher.group(); 49 | Token token = Token.builder().type(tokenType).value(value).rowNumber(rowNumber).build(); 50 | tokens.add(token); 51 | 52 | if (tokenType == TokenType.LineBreak) { 53 | rowNumber++; 54 | } 55 | } 56 | 57 | return matcher.group().length(); 58 | } 59 | } 60 | String problem = ErrorConstants.SYNTAX_GALAT_HAI; 61 | String solution = String.format("Invalid expression at line %d", rowNumber); 62 | System.out.println("Poblem : "+problem); 63 | System.out.println("Solution : "+solution); 64 | throw new SyntaxException(problem,solution); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/Operators/ClassPropertyOperator.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions.Operators; 2 | 3 | import org.prakarshs.Context.ExceptionContext; 4 | import org.prakarshs.Syntax.Expressions.AssignExpression; 5 | import org.prakarshs.Syntax.Expressions.Expression; 6 | import org.prakarshs.Syntax.Expressions.FunctionExpression; 7 | import org.prakarshs.Syntax.Expressions.VariableExpression; 8 | import org.prakarshs.Syntax.Values.ClassValue; 9 | import org.prakarshs.Syntax.Values.ThisValue; 10 | import org.prakarshs.Syntax.Values.Value; 11 | 12 | public class ClassPropertyOperator extends BinaryOperatorExpression implements AssignExpression { 13 | public ClassPropertyOperator(Expression left, Expression right) { 14 | super(left, right); 15 | } 16 | 17 | @Override 18 | public Value evaluate() { 19 | Value left = getLeft().evaluate(); 20 | if (left == null) return null; 21 | 22 | // access class's property via this instance 23 | // this :: class_argument 24 | if (left instanceof ThisValue) { 25 | left = ((ThisValue) left).getValue(); 26 | } 27 | 28 | if (left instanceof ClassValue) { 29 | if (getRight() instanceof VariableExpression) { 30 | // access class's property 31 | // new Class [] :: class_property 32 | return ((ClassValue) left).getValue(((VariableExpression) getRight()).getName()); 33 | } else if (getRight() instanceof FunctionExpression) { 34 | // execute class's function 35 | // new Class [] :: class_function [] 36 | return ((FunctionExpression) getRight()).evaluate((ClassValue) left); 37 | } 38 | } 39 | 40 | return ExceptionContext.raiseException(String.format("Class Ki Property Access Nahi Kar Pa Raha Mehta Saab `%s``", getRight())); 41 | } 42 | 43 | @Override 44 | public Value assign(Value value) { 45 | Value left = getLeft().evaluate(); 46 | if (left == null) return null; 47 | 48 | // access class's property via this instance 49 | // this :: class_argument 50 | if (left instanceof ThisValue) { 51 | left = ((ThisValue) left).getValue(); 52 | } 53 | 54 | if (left instanceof ClassValue && getRight() instanceof VariableExpression) { 55 | String propertyName = ((VariableExpression) getRight()).getName(); 56 | ((ClassValue) left).setValue(propertyName, value); 57 | } 58 | return left; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/HandleExceptionStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.ExceptionContext; 5 | import org.prakarshs.Context.MemoryContext; 6 | 7 | @Getter 8 | public class HandleExceptionStatement extends Statement { 9 | private final CompositeStatement beginStatement; 10 | private final CompositeStatement rescueStatement; 11 | private final CompositeStatement ensureStatement; 12 | private final String errorVariable; 13 | 14 | public HandleExceptionStatement(Integer rowNumber, String blockName, CompositeStatement beginStatement, 15 | CompositeStatement rescueStatement, CompositeStatement ensureStatement, String errorVariable) { 16 | super(rowNumber, blockName); 17 | this.beginStatement = beginStatement; 18 | this.rescueStatement = rescueStatement; 19 | this.ensureStatement = ensureStatement; 20 | this.errorVariable = errorVariable; 21 | } 22 | 23 | @Override 24 | public void execute() { 25 | MemoryContext.pushScope(MemoryContext.newScope()); 26 | try { 27 | beginStatement.execute(); 28 | } finally { 29 | MemoryContext.endScope(); 30 | } 31 | 32 | // rescue block 33 | if (rescueStatement != null && ExceptionContext.isRaised()) { 34 | 35 | MemoryContext.pushScope(MemoryContext.newScope()); 36 | if (errorVariable != null) { 37 | MemoryContext.getScope().setLocal(errorVariable, ExceptionContext.getException().getValue()); 38 | } 39 | 40 | ExceptionContext.rescueException(); 41 | 42 | try { 43 | rescueStatement.execute(); 44 | } finally { 45 | MemoryContext.endScope(); 46 | } 47 | } 48 | 49 | // ensure block 50 | if (ensureStatement != null) { 51 | boolean raised = ExceptionContext.isRaised(); 52 | if (raised) { 53 | // ensure block shouldn't accumulate stack trace 54 | ExceptionContext.disable(); 55 | } 56 | 57 | MemoryContext.pushScope(MemoryContext.newScope()); 58 | try { 59 | ensureStatement.execute(); 60 | } finally { 61 | MemoryContext.endScope(); 62 | if (raised) { 63 | // continue to accumulate stack trace 64 | ExceptionContext.enable(); 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Statements/Loops/AbstractLoopStatement.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Statements.Loops; 2 | 3 | import org.prakarshs.Context.*; 4 | import org.prakarshs.Syntax.Statements.Statement; 5 | import org.prakarshs.Syntax.Statements.CompositeStatement; 6 | 7 | public abstract class AbstractLoopStatement extends CompositeStatement { 8 | public AbstractLoopStatement(Integer rowNumber, String blockName) { 9 | super(rowNumber, blockName); 10 | } 11 | 12 | protected abstract void init(); 13 | 14 | protected abstract boolean hasNext(); 15 | 16 | protected abstract void preIncrement(); 17 | 18 | protected abstract void postIncrement(); 19 | 20 | @Override 21 | public void execute() { 22 | // memory scope for counter variables 23 | MemoryContext.pushScope(MemoryContext.newScope()); 24 | try { 25 | 26 | // init loop 27 | init(); 28 | 29 | while (hasNext()) { 30 | preIncrement(); 31 | 32 | // isolated memory scope for each iteration 33 | MemoryContext.pushScope(MemoryContext.newScope()); 34 | 35 | try { 36 | 37 | // execute inner statements 38 | for (Statement statement : getStatements2Execute()) { 39 | statement.execute(); 40 | 41 | // stop the execution in case Exception occurred 42 | if (ExceptionContext.isRaised()) 43 | return; 44 | 45 | // stop the execution in case ReturnStatement is invoked 46 | if (ReturnContext.getScope().isInvoked()) 47 | return; 48 | 49 | // stop the execution in case BreakStatement is invoked 50 | if (BreakContext.getScope().isInvoked()) 51 | return; 52 | 53 | // jump to the next iteration in case NextStatement is invoked 54 | if (NextContext.getScope().isInvoked()) 55 | break; 56 | } 57 | } finally { 58 | NextContext.reset(); 59 | MemoryContext.endScope(); // release each iteration memory 60 | 61 | // increment the counter even if the NextStatement is called 62 | postIncrement(); 63 | } 64 | 65 | } 66 | } finally { 67 | MemoryContext.endScope(); // release loop memory 68 | BreakContext.reset(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/MemoryScope.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import org.prakarshs.Syntax.Values.NullValue; 4 | import org.prakarshs.Syntax.Values.Value; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * Contains variables defined in a block of code 11 | *

12 | * 13 | * @see ValueReference 14 | * @see MemoryContext 15 | * @see Value 16 | */ 17 | public class MemoryScope { 18 | /** 19 | * Variables defined in this block 20 | */ 21 | private final Map variables; 22 | /** 23 | * Parent MemoryScope to access the variables defined in outer scopes 24 | */ 25 | private final MemoryScope parent; 26 | 27 | public MemoryScope(MemoryScope parent) { 28 | this.variables = new HashMap<>(); 29 | this.parent = parent; 30 | } 31 | 32 | /** 33 | * Get variable value from the current scope or in the outer scopes 34 | *

35 | * 36 | * @return {@link NullValue} if there is no variable defined 37 | */ 38 | public Value get(String name) { 39 | ValueReference variable = variables.get(name); 40 | if (variable != null) 41 | return variable.getValue(); 42 | else if (parent != null) 43 | return parent.get(name); 44 | else 45 | return NullValue.NULL_INSTANCE; 46 | } 47 | 48 | /** 49 | * Get variable from the current scope 50 | */ 51 | public Value getLocal(String name) { 52 | ValueReference variable = variables.get(name); 53 | return variable != null ? variable.getValue() : null; 54 | } 55 | 56 | /** 57 | * Set variable's value to the current scope 58 | */ 59 | public void set(String name, Value value) { 60 | MemoryScope variableScope = findScope(name); 61 | if (variableScope == null) { 62 | setLocal(name, value); 63 | } else { 64 | variableScope.setLocal(name, value); 65 | } 66 | } 67 | 68 | /** 69 | * Set variable's value directly using {@link ValueReference} in the current scope 70 | */ 71 | public void setLocal(String name, ValueReference variable) { 72 | variables.put(name, variable); 73 | } 74 | 75 | /** 76 | * Set variable's value in the current scope 77 | */ 78 | public void setLocal(String name, Value value) { 79 | if (variables.containsKey(name)) { 80 | variables.get(name).setValue(value); 81 | } else { 82 | variables.put(name, ValueReference.instanceOf(value)); 83 | } 84 | } 85 | 86 | private MemoryScope findScope(String name) { 87 | if (variables.containsKey(name)) 88 | return this; 89 | return parent == null ? null : parent.findScope(name); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Values/ClassValue.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Values; 2 | 3 | import lombok.Getter; 4 | import org.prakarshs.Context.MemoryContext; 5 | import org.prakarshs.Context.MemoryScope; 6 | import org.prakarshs.Context.definition.ClassDefinition; 7 | 8 | import java.util.Iterator; 9 | import java.util.Map; 10 | import java.util.stream.Collectors; 11 | 12 | import static org.prakarshs.Syntax.Values.NullValue.NULL_INSTANCE; 13 | 14 | @Getter 15 | public class ClassValue extends IterableValue { 16 | private final MemoryScope memoryScope; 17 | // contains ClassValue for the Derived class and all the Base classes chain that Derived class inherits 18 | private final Map relations; 19 | 20 | public ClassValue(ClassDefinition definition, MemoryScope memoryScope, Map relations) { 21 | super(definition); 22 | this.memoryScope = memoryScope; 23 | this.relations = relations; 24 | } 25 | 26 | public ClassValue getRelation(String name) { 27 | return relations.get(name); 28 | } 29 | 30 | public boolean containsRelation(String name) { 31 | return relations.containsKey(name); 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | MemoryContext.pushScope(memoryScope); 37 | try { 38 | return getValue().getClassDetails().getProperties().stream() 39 | .map(t -> t + " = " + getValue(t)) 40 | .collect(Collectors.joining(", ", getValue().getClassDetails().getName() + " [ ", " ]")); 41 | } finally { 42 | MemoryContext.endScope(); 43 | } 44 | } 45 | 46 | public Value getValue(String name) { 47 | MemoryContext.pushScope(memoryScope); 48 | try { 49 | Value result = MemoryContext.getScope().getLocal(name); 50 | return result != null ? result : NULL_INSTANCE; 51 | } finally { 52 | MemoryContext.endScope(); 53 | } 54 | } 55 | 56 | public void setValue(String name, Value value) { 57 | MemoryContext.pushScope(memoryScope); 58 | try { 59 | MemoryContext.getScope().setLocal(name, value); 60 | } finally { 61 | MemoryContext.endScope(); 62 | } 63 | } 64 | 65 | @Override 66 | public boolean equals(Object o) { 67 | if (this == o) return true; 68 | if (o == null) return false; 69 | if (getClass() != o.getClass()) return false; 70 | ClassValue oValue = (ClassValue) o; 71 | 72 | return getValue() 73 | .getClassDetails() 74 | .getProperties() 75 | .stream() 76 | .allMatch(e -> getValue(e).equals(oValue.getValue(e))); 77 | } 78 | 79 | @Override 80 | public Iterator> iterator() { 81 | return getValue() 82 | .getClassDetails() 83 | .getProperties() 84 | .stream() 85 | .>map(this::getValue) 86 | .iterator(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/definition/DefinitionScope.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context.definition; 2 | 3 | import lombok.Getter; 4 | 5 | import java.util.HashSet; 6 | import java.util.Objects; 7 | import java.util.Optional; 8 | import java.util.Set; 9 | 10 | /** 11 | * Contains structures (classes, functions) defined in a block of code 12 | *

13 | * 14 | * @see ClassDefinition 15 | * @see FunctionDefinition 16 | * @see DefinitionContext 17 | */ 18 | public class DefinitionScope { 19 | /** 20 | * Classes defined in the block 21 | */ 22 | private final Set classes; 23 | /** 24 | * Functions declared in the block 25 | */ 26 | private final Set functions; 27 | /** 28 | * Parent DefinitionScope to access the structures defined in outer blocks of code 29 | */ 30 | @Getter 31 | private final DefinitionScope parent; 32 | 33 | public DefinitionScope(DefinitionScope parent) { 34 | this.classes = new HashSet<>(); 35 | this.functions = new HashSet<>(); 36 | this.parent = parent; 37 | } 38 | 39 | /** 40 | * Get ClassDefinition from the current block and from outer blocks of code 41 | * 42 | * @param name name of the class 43 | */ 44 | public ClassDefinition getClass(String name) { 45 | Optional classDefinition = classes.stream() 46 | .filter(t -> t.getClassDetails().getName().equals(name)) 47 | .findAny(); 48 | if (classDefinition.isPresent()) 49 | return classDefinition.get(); 50 | else if (parent != null) 51 | return parent.getClass(name); 52 | else 53 | return null; 54 | } 55 | 56 | /** 57 | * Add ClassDefinition to the current block 58 | */ 59 | public void addClass(ClassDefinition classDefinition) { 60 | classes.add(classDefinition); 61 | } 62 | 63 | /** 64 | * Get FunctionDefinition from the current block and from outer blocks of code 65 | * 66 | * @param name name of the function 67 | * @param argumentsSize count of function arguments, useful in case there are multiple functions with the same name but with different length of arguments declared 68 | */ 69 | public FunctionDefinition getFunction(String name, int argumentsSize) { 70 | Optional functionDefinition = functions.stream() 71 | .filter(t -> Objects.equals(t.getDetails().getName(), name) 72 | && Objects.equals(t.getDetails().getArguments().size(), argumentsSize)) 73 | .findAny(); 74 | if (functionDefinition.isPresent()) 75 | return functionDefinition.get(); 76 | else if (parent != null) 77 | return parent.getFunction(name, argumentsSize); 78 | else 79 | return null; 80 | } 81 | 82 | /** 83 | * Check that DefinitionScope contains the function 84 | * 85 | * @param name name of the function 86 | * @param argumentsSize amount of function arguments in case there are multiple functions with the same name declared 87 | */ 88 | public boolean containsFunction(String name, int argumentsSize) { 89 | return getFunction(name, argumentsSize) != null; 90 | } 91 | 92 | /** 93 | * Add FunctionDefinition to the current block 94 | */ 95 | public void addFunction(FunctionDefinition functionDefinition) { 96 | functions.add(functionDefinition); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Tokens/TokensStack.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Tokens; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.apache.commons.lang3.ArrayUtils; 5 | import org.prakarshs.Constants.ErrorConstants; 6 | import org.prakarshs.Exceptions.SyntaxException; 7 | 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.Objects; 11 | import java.util.stream.Stream; 12 | 13 | @RequiredArgsConstructor 14 | public class TokensStack { 15 | private final List tokens; 16 | private int position; 17 | 18 | private static final List EMPTY_TOKENS = List.of(TokenType.LineBreak, TokenType.Comment); 19 | 20 | public Token next(TokenType type, TokenType... types) { 21 | skipEmptyTokens(); 22 | TokenType[] tokenTypes = ArrayUtils.add(types, type); 23 | if (position < tokens.size()) { 24 | Token token = tokens.get(position); 25 | if (Stream.of(tokenTypes).anyMatch(t -> t == token.getType())) { 26 | position++; 27 | return token; 28 | } 29 | } 30 | 31 | String problem = ErrorConstants.SYNTAX_GALAT_HAI; 32 | String solution = String.format(String.format("After `%s` declaration expected any of the following lexemes `%s`", previous(), Arrays.toString(tokenTypes))); 33 | System.out.println("Poblem : "+problem); 34 | System.out.println("Solution : "+solution); 35 | throw new SyntaxException(problem,solution); 36 | } 37 | 38 | public void back() { 39 | position--; 40 | } 41 | 42 | public boolean hasNext() { 43 | skipEmptyTokens(); 44 | return position < tokens.size(); 45 | } 46 | 47 | public Token next(TokenType type, String value, String... values) { 48 | skipEmptyTokens(); 49 | if (position < tokens.size()) { 50 | String[] allValues = ArrayUtils.add(values, value); 51 | Token token = tokens.get(position); 52 | if (token.getType() == type && Arrays.stream(allValues).anyMatch(t -> Objects.equals(t, token.getValue()))) { 53 | position++; 54 | return token; 55 | } 56 | } 57 | String problem = ErrorConstants.SYNTAX_GALAT_HAI; 58 | String solution = String.format(String.format("After `%s` declaration expected `%s, %s` lexeme", previous(), type, value)); 59 | System.out.println("Poblem : "+problem); 60 | System.out.println("Solution : "+solution); 61 | throw new SyntaxException(problem,solution); 62 | } 63 | 64 | public Token next() { 65 | skipEmptyTokens(); 66 | return tokens.get(position++); 67 | } 68 | 69 | public boolean peek(TokenType type, String value, String... values) { 70 | skipEmptyTokens(); 71 | return peekSameLine(type, value, values); 72 | } 73 | 74 | public boolean peekSameLine(TokenType type, String value, String... values) { 75 | if (position < tokens.size()) { 76 | String[] allValues = ArrayUtils.add(values, value); 77 | Token token = tokens.get(position); 78 | return type == token.getType() && Arrays.stream(allValues).anyMatch(t -> Objects.equals(t, token.getValue())); 79 | } 80 | return false; 81 | } 82 | 83 | public boolean peek(TokenType type, TokenType... types) { 84 | skipEmptyTokens(); 85 | return peekSameLine(type, types); 86 | } 87 | 88 | public boolean peekSameLine(TokenType type, TokenType... types) { 89 | if (position < tokens.size()) { 90 | TokenType[] tokenTypes = ArrayUtils.add(types, type); 91 | Token token = tokens.get(position); 92 | return Stream.of(tokenTypes).anyMatch(t -> t == token.getType()); 93 | } 94 | return false; 95 | } 96 | 97 | private Token previous() { 98 | return tokens.get(position - 1); 99 | } 100 | 101 | private void skipEmptyTokens() { 102 | while (position != tokens.size() && EMPTY_TOKENS.contains(tokens.get(position).getType())) 103 | position++; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | org.example 7 | Jhethia 8 | 0.0.10 9 | 10 | 11 | 12 | central2 13 | Central Repository 14 | https://repo.maven.apache.org/maven2 15 | default 16 | 17 | false 18 | 19 | 20 | 21 | central 22 | Maven Central 23 | default 24 | https://repo1.maven.org/maven2 25 | 26 | false 27 | 28 | 29 | 30 | 31 | 32 | 11 33 | ${java.version} 34 | ${java.version} 35 | 5.9.2 36 | 3.12.0 37 | 1.18.26 38 | 39 | 40 | 41 | 42 | org.apache.commons 43 | commons-lang3 44 | ${commons-lang3.version} 45 | 46 | 47 | 48 | org.projectlombok 49 | lombok 50 | ${lombok.version} 51 | provided 52 | 53 | 54 | 55 | 56 | org.junit.jupiter 57 | junit-jupiter-engine 58 | ${junit.version} 59 | test 60 | 61 | 62 | org.junit.jupiter 63 | junit-jupiter-api 64 | ${junit.version} 65 | test 66 | 67 | 68 | 69 | 70 | ${project.artifactId} 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-compiler-plugin 75 | 3.11.0 76 | 77 | ${java.version} 78 | ${java.version} 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-surefire-plugin 84 | 3.0.0 85 | 86 | 87 | org.apache.maven.plugins 88 | maven-shade-plugin 89 | 3.4.1 90 | 91 | 92 | package 93 | 94 | shade 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Context/ExceptionContext.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Context; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.prakarshs.Syntax.Values.TextValue; 6 | import org.prakarshs.Syntax.Values.Value; 7 | import org.prakarshs.Syntax.Statements.HandleExceptionStatement; 8 | import org.prakarshs.Syntax.Statements.RaiseExceptionStatement; 9 | import org.prakarshs.Syntax.Statements.Statement; 10 | 11 | import java.util.List; 12 | import java.util.Stack; 13 | import java.util.stream.Collectors; 14 | 15 | /** 16 | * Associates thrown {@link Exception} with the current execution statement 17 | *

18 | * 19 | * @see RaiseExceptionStatement 20 | * @see HandleExceptionStatement 21 | */ 22 | public class ExceptionContext { 23 | /** 24 | * Raised exception 25 | */ 26 | @Getter 27 | private static Exception exception; 28 | /** 29 | * State of the exception 30 | */ 31 | private static State state = State.NONE; 32 | 33 | /** 34 | * Raise an exception 35 | *

36 | * 37 | * @param value raised value 38 | * @return null 39 | */ 40 | public static Value raiseException(Value value) { 41 | exception = new Exception(value, new Stack<>()); 42 | state = State.RAISED; 43 | return null; 44 | } 45 | 46 | /** 47 | * Raise an exception 48 | *

49 | * 50 | * @param textValue raised text value 51 | * @return null 52 | */ 53 | public static Value raiseException(String textValue) { 54 | return raiseException(new TextValue(textValue)); 55 | } 56 | 57 | /** 58 | * Rescue the exception if it's been handled 59 | */ 60 | public static void rescueException() { 61 | exception = null; 62 | state = State.NONE; 63 | } 64 | 65 | /** 66 | * Disable collecting of the stack trace records before executing ensure block 67 | */ 68 | public static void disable() { 69 | state = State.DISABLED; 70 | } 71 | 72 | /** 73 | * Enable collecting the stack trace after quiting the ensure block 74 | */ 75 | public static void enable() { 76 | state = State.RAISED; 77 | } 78 | 79 | /** 80 | * If an exception's been raised 81 | */ 82 | public static boolean isRaised() { 83 | return state == State.RAISED; 84 | } 85 | 86 | /** 87 | * Add record of the application's movement as a statement that initiated the exception 88 | */ 89 | public static void addTracedStatement(Statement statement) { 90 | if (isRaised()) { 91 | exception.stackTrace.add(statement); 92 | } 93 | } 94 | 95 | /** 96 | * Print an exception 97 | */ 98 | public static void printStackTrace() { 99 | System.err.println(exception); 100 | rescueException(); 101 | } 102 | 103 | /** 104 | * Exception details 105 | */ 106 | @RequiredArgsConstructor 107 | @Getter 108 | public static class Exception { 109 | /** 110 | * Raised error 111 | */ 112 | private final Value value; 113 | /** 114 | * Statements containing records of the application's movement leading to the statement that initiated the exception 115 | */ 116 | private final List stackTrace; 117 | 118 | @Override 119 | public String toString() { 120 | return String.format("%s%n%s", 121 | value, 122 | stackTrace 123 | .stream() 124 | .map(st -> String.format("%4sat %s:%d", "", st.getBlockName(), st.getRowNumber())) 125 | .collect(Collectors.joining("\n")) 126 | ); 127 | } 128 | } 129 | 130 | /** 131 | * States of the ExceptionContext 132 | */ 133 | private enum State { 134 | /** 135 | * No exception raised or the exception is rescued 136 | */ 137 | NONE, 138 | /** 139 | * The exception is raised 140 | */ 141 | RAISED, 142 | /** 143 | * The exception disabled to execute ensure block 144 | */ 145 | DISABLED 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/ClassExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | 7 | import org.prakarshs.Context.definition.ClassDefinition; 8 | import org.prakarshs.Context.definition.DefinitionContext; 9 | import org.prakarshs.Syntax.Values.ClassValue; 10 | import org.prakarshs.Syntax.Values.NullValue; 11 | import org.prakarshs.Syntax.Values.Value; 12 | import org.prakarshs.Syntax.Statements.ClassStatement; 13 | import org.prakarshs.Context.*; 14 | 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | import java.util.stream.Collectors; 20 | import java.util.stream.IntStream; 21 | 22 | @RequiredArgsConstructor 23 | @Getter 24 | @ToString(onlyExplicitlyIncluded = true) 25 | public class ClassExpression implements Expression { 26 | @ToString.Include 27 | private final String name; 28 | private final List propertiesExpressions; 29 | // contains Derived class and all the Base classes chain that Derived class inherits 30 | private final Map relations; 31 | 32 | public ClassExpression(String name, List propertiesExpressions) { 33 | this(name, propertiesExpressions, new HashMap<>()); 34 | } 35 | 36 | @Override 37 | public Value evaluate() { 38 | //initialize class's properties 39 | List values = new ArrayList<>(propertiesExpressions.size()); 40 | for (Expression expression : propertiesExpressions) { 41 | ValueReference value = ValueReference.instanceOf(expression); 42 | if (value == null) return null; 43 | values.add(value); 44 | } 45 | return evaluate(values); 46 | } 47 | 48 | /** 49 | * Evaluate nested class 50 | * 51 | * @param classValue instance of the parent class 52 | */ 53 | public Value evaluate(ClassValue classValue) { 54 | //initialize class's properties 55 | List values = new ArrayList<>(propertiesExpressions.size()); 56 | for (Expression expression : propertiesExpressions) { 57 | ValueReference value = ValueReference.instanceOf(expression); 58 | if (value == null) return null; 59 | values.add(value); 60 | } 61 | 62 | //set parent class's definition 63 | ClassDefinition classDefinition = classValue.getValue(); 64 | DefinitionContext.pushScope(classDefinition.getDefinitionScope()); 65 | 66 | try { 67 | return evaluate(values); 68 | } finally { 69 | DefinitionContext.endScope(); 70 | } 71 | } 72 | 73 | private Value evaluate(List values) { 74 | //get class's definition and statement 75 | ClassDefinition definition = DefinitionContext.getScope().getClass(name); 76 | if (definition == null) { 77 | return ExceptionContext.raiseException(String.format("Kilass `%s` is not defined", name)); 78 | } 79 | ClassStatement classStatement = definition.getStatement(); 80 | 81 | //set separate scope 82 | MemoryScope classScope = new MemoryScope(null); 83 | MemoryContext.pushScope(classScope); 84 | 85 | //initialize constructor arguments 86 | ClassValue classValue = new ClassValue(definition, classScope, relations); 87 | relations.put(name, classValue); 88 | 89 | // fill the missing properties with NullValue.NULL_INSTANCE 90 | // class A [arg1, arg2] 91 | // new A [arg1] -> new A [arg1, null] 92 | // new A [arg1, arg2, arg3] -> new A [arg1, arg2] 93 | List valuesToSet = IntStream.range(0, definition.getClassDetails().getProperties().size()) 94 | .boxed() 95 | .map(i -> values.size() > i ? values.get(i) : ValueReference.instanceOf(NullValue.NULL_INSTANCE)) 96 | .collect(Collectors.toList()); 97 | 98 | //invoke constructors of the base classes and set a ClassValue relation 99 | definition.getBaseTypes() 100 | .stream() 101 | .map(baseType -> { 102 | // initialize base class's properties 103 | // class A [a_arg] 104 | // class B [b_arg1, b_arg2]: A [b_arg1] 105 | List baseClassProperties = baseType.getProperties().stream() 106 | .map(t -> definition.getClassDetails().getProperties().indexOf(t)) 107 | .map(valuesToSet::get) 108 | .collect(Collectors.toList()); 109 | return new ClassExpression(baseType.getName(), baseClassProperties, relations); 110 | }) 111 | .forEach(ClassExpression::evaluate); 112 | 113 | try { 114 | ClassInstanceContext.pushValue(classValue); 115 | IntStream.range(0, definition.getClassDetails().getProperties().size()).boxed() 116 | .forEach(i -> MemoryContext.getScope() 117 | .setLocal(definition.getClassDetails().getProperties().get(i), valuesToSet.get(i))); 118 | 119 | //execute function body 120 | DefinitionContext.pushScope(definition.getDefinitionScope()); 121 | try { 122 | classStatement.execute(); 123 | } finally { 124 | DefinitionContext.endScope(); 125 | } 126 | 127 | // if exception have been thrown in the constructor 128 | if (ExceptionContext.isRaised()) 129 | return null; 130 | 131 | return classValue; 132 | } finally { 133 | MemoryContext.endScope(); 134 | ClassInstanceContext.popValue(); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/FunctionExpression.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.ToString; 6 | import org.prakarshs.Context.definition.*; 7 | import org.prakarshs.Syntax.Values.ClassValue; 8 | import org.prakarshs.Syntax.Values.NullValue; 9 | import org.prakarshs.Syntax.Values.Value; 10 | import org.prakarshs.Syntax.Statements.FunctionStatement; 11 | import org.prakarshs.Context.*; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.stream.Collectors; 16 | import java.util.stream.IntStream; 17 | 18 | @RequiredArgsConstructor 19 | @Getter 20 | @ToString(onlyExplicitlyIncluded = true) 21 | public class FunctionExpression implements Expression { 22 | @ToString.Include 23 | private final String name; 24 | private final List argumentExpressions; 25 | 26 | @Override 27 | public Value evaluate() { 28 | //initialize function arguments 29 | List> values = new ArrayList<>(argumentExpressions.size()); 30 | for (Expression expression : argumentExpressions) { 31 | Value value = expression.evaluate(); 32 | if (value == null) return null; 33 | values.add(value); 34 | } 35 | return evaluate(values); 36 | } 37 | 38 | /** 39 | * Evaluate class's function 40 | * 41 | * @param classValue instance of class where the function is placed in 42 | */ 43 | public Value evaluate(ClassValue classValue) { 44 | //initialize function arguments 45 | List> values = new ArrayList<>(argumentExpressions.size()); 46 | for (Expression expression : argumentExpressions) { 47 | Value value = expression.evaluate(); 48 | if (value == null) return null; 49 | values.add(value); 50 | } 51 | 52 | // find a class containing the function 53 | ClassDefinition classDefinition = findClassDefinitionContainingFunction(classValue.getValue(), name, values.size()); 54 | if (classDefinition == null) { 55 | String args = IntStream.range(0, values.size()).mapToObj(t -> "arg" + (t + 1)).collect(Collectors.joining(", ")); 56 | return ExceptionContext.raiseException(String.format("Function `%s#%s [%s]` is not defined", 57 | classValue.getValue().getClassDetails().getName(), name, args)); 58 | } 59 | DefinitionScope classDefinitionScope = classDefinition.getDefinitionScope(); 60 | ClassValue functionClassValue = classValue.getRelation(classDefinition.getClassDetails().getName()); 61 | MemoryScope memoryScope = functionClassValue.getMemoryScope(); 62 | 63 | //set class's definition and memory scopes 64 | DefinitionContext.pushScope(classDefinitionScope); 65 | MemoryContext.pushScope(memoryScope); 66 | ClassInstanceContext.pushValue(functionClassValue); 67 | 68 | try { 69 | //proceed function 70 | return evaluate(values); 71 | } finally { 72 | DefinitionContext.endScope(); 73 | MemoryContext.endScope(); 74 | ClassInstanceContext.popValue(); 75 | } 76 | } 77 | 78 | private Value evaluate(List> values) { 79 | //get function's definition and statement 80 | FunctionDefinition definition = DefinitionContext.getScope().getFunction(name, values.size()); 81 | if (definition == null) { 82 | String args = IntStream.range(0, values.size()).mapToObj(t -> "arg" + (t + 1)).collect(Collectors.joining(", ")); 83 | return ExceptionContext.raiseException(String.format("Function `%s [%s]` is not defined", name, args)); 84 | } 85 | FunctionStatement statement = definition.getStatement(); 86 | FunctionDetails details = definition.getDetails(); 87 | 88 | //set new memory scope 89 | MemoryContext.pushScope(MemoryContext.newScope()); 90 | 91 | try { 92 | //initialize function arguments 93 | IntStream.range(0, details.getArguments().size()).boxed() 94 | .forEach(i -> MemoryContext.getScope() 95 | .setLocal(details.getArguments().get(i), values.size() > i ? values.get(i) : NullValue.NULL_INSTANCE)); 96 | 97 | //execute function body 98 | statement.execute(); 99 | 100 | //obtain function result 101 | return ReturnContext.getScope().getResult(); 102 | } finally { 103 | // release function memory and return context 104 | MemoryContext.endScope(); 105 | ReturnContext.reset(); 106 | } 107 | } 108 | 109 | /** 110 | * Find a Base class that contains the required function 111 | * 112 | *

{@code
113 |      * class A
114 |      *      fun action
115 |      *      end
116 |      * end
117 |      *
118 |      * class B
119 |      * end
120 |      *
121 |      * b = new B
122 |      * # Function `action` is not available from the DefinitionScope of class B as it's declared in the class A
123 |      * b :: action []
124 |      *
125 |      * }
126 | */ 127 | private ClassDefinition findClassDefinitionContainingFunction(ClassDefinition classDefinition, String functionName, int argumentsSize) { 128 | DefinitionScope definitionScope = classDefinition.getDefinitionScope(); 129 | if (definitionScope.containsFunction(functionName, argumentsSize)) { 130 | return classDefinition; 131 | } else { 132 | for (ClassDetails baseType : classDefinition.getBaseTypes()) { 133 | ClassDefinition baseTypeDefinition = definitionScope.getClass(baseType.getName()); 134 | ClassDefinition functionClassDefinition = findClassDefinitionContainingFunction(baseTypeDefinition, functionName, argumentsSize); 135 | if (functionClassDefinition != null) 136 | return functionClassDefinition; 137 | } 138 | return null; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Syntax/Expressions/ExpressionReader.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Syntax.Expressions; 2 | 3 | import lombok.Getter; 4 | import lombok.SneakyThrows; 5 | import org.prakarshs.Constants.ErrorConstants; 6 | import org.prakarshs.Exceptions.SyntaxException; 7 | import org.prakarshs.Syntax.Expressions.Operators.*; 8 | import org.prakarshs.Syntax.Values.LogicalValue; 9 | import org.prakarshs.Syntax.Values.NumericValue; 10 | import org.prakarshs.Syntax.Values.TextValue; 11 | import org.prakarshs.Tokens.Token; 12 | import org.prakarshs.Tokens.TokenType; 13 | import org.prakarshs.Tokens.TokensStack; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Objects; 18 | import java.util.Stack; 19 | 20 | import static org.prakarshs.Syntax.Values.NullValue.NULL_INSTANCE; 21 | import static org.prakarshs.Syntax.Values.ThisValue.THIS_INSTANCE; 22 | 23 | public class ExpressionReader { 24 | private final Stack operands; 25 | private final Stack operators; 26 | @Getter 27 | private final TokensStack tokens; 28 | 29 | private ExpressionReader(TokensStack tokens) { 30 | this.operands = new Stack<>(); 31 | this.operators = new Stack<>(); 32 | this.tokens = tokens; 33 | } 34 | 35 | public static Expression readExpression(TokensStack tokens) { 36 | ExpressionReader expressionReader = new ExpressionReader(tokens); 37 | return expressionReader.readExpression(); 38 | } 39 | 40 | public static Expression readExpression(ExpressionReader expressionReader) { 41 | return readExpression(expressionReader.getTokens()); 42 | } 43 | 44 | private boolean hasNextToken() { 45 | if (tokens.peekSameLine(TokenType.Operator, TokenType.Variable, TokenType.Numeric, TokenType.Logical, 46 | TokenType.Null, TokenType.This, TokenType.Text)) 47 | return true; 48 | //beginning of an array 49 | if (tokens.peekSameLine(TokenType.GroupDivider, "{")) 50 | return true; 51 | return false; 52 | } 53 | 54 | private Expression readExpression() { 55 | while (hasNextToken()) { 56 | Token token = tokens.next(); 57 | switch (token.getType()) { 58 | case Operator: 59 | Operator operator = Operator.getType(token.getValue()); 60 | switch (operator) { 61 | case LeftParen: 62 | operators.push(operator); 63 | break; 64 | case RightParen: 65 | //until left bracket is not reached 66 | while (!operators.empty() && operators.peek() != Operator.LeftParen) 67 | applyTopOperator(); 68 | operators.pop(); //pop left bracket 69 | break; 70 | default: 71 | //until top operator has greater precedence 72 | while (!operators.isEmpty() && operators.peek().greaterThan(operator)) 73 | applyTopOperator(); 74 | operators.push(operator); // finally, add less prioritized operator 75 | } 76 | break; 77 | default: 78 | String value = token.getValue(); 79 | Expression operand; 80 | switch (token.getType()) { 81 | case Numeric: 82 | operand = new NumericValue(Double.parseDouble(value)); 83 | break; 84 | case Logical: 85 | operand = new LogicalValue(Boolean.valueOf(value)); 86 | break; 87 | case Text: 88 | operand = new TextValue(value); 89 | break; 90 | case GroupDivider: 91 | if (Objects.equals(token.getValue(), "{")) { 92 | operand = readArrayInstance(); 93 | break; 94 | } 95 | case Null: 96 | operand = NULL_INSTANCE; 97 | break; 98 | case This: 99 | operand = THIS_INSTANCE; 100 | break; 101 | case Variable: 102 | default: 103 | if (!operators.isEmpty() && List.of(Operator.ClassInstance, Operator.NestedClassInstance).contains(operators.peek())) { 104 | operand = readClassInstance(token); 105 | } else if (tokens.peekSameLine(TokenType.GroupDivider, "[")) { 106 | operand = readFunctionInvocation(token); 107 | } else if (tokens.peekSameLine(TokenType.GroupDivider, "{")) { 108 | operand = readArrayValue(token); 109 | } else { 110 | operand = new VariableExpression(value); 111 | } 112 | } 113 | operands.push(operand); 114 | } 115 | } 116 | 117 | while (!operators.isEmpty()) { 118 | applyTopOperator(); 119 | } 120 | 121 | if (operands.isEmpty()) { 122 | return NULL_INSTANCE; 123 | } else { 124 | return operands.pop(); 125 | } 126 | } 127 | 128 | @SneakyThrows 129 | private void applyTopOperator() { 130 | // e.g. a + b 131 | Operator operator = operators.pop(); 132 | Class operatorType = operator.getType(); 133 | Expression left = operands.pop(); 134 | if (BinaryOperatorExpression.class.isAssignableFrom(operatorType)) { 135 | Expression right = operands.pop(); 136 | operands.push(operatorType 137 | .getConstructor(Expression.class, Expression.class) 138 | .newInstance(right, left)); 139 | } else if (UnaryOperatorExpression.class.isAssignableFrom(operatorType)) { 140 | // e.g. new Instance [] 141 | operands.push(operatorType 142 | .getConstructor(Expression.class) 143 | .newInstance(left)); 144 | } else { 145 | String problem = ErrorConstants.SYNTAX_GALAT_HAI; 146 | String solution = String.format(String.format("Operator `%s` is not supported", operatorType)); 147 | System.out.println("Poblem : "+problem); 148 | System.out.println("Solution : "+solution); 149 | throw new SyntaxException(problem,solution); 150 | 151 | } 152 | } 153 | 154 | // read class instance: new Class [ property1, property2, ... ] 155 | private ClassExpression readClassInstance(Token token) { // token contains class name 156 | List properties = new ArrayList<>(); 157 | if (tokens.peekSameLine(TokenType.GroupDivider, "[")) { 158 | 159 | tokens.next(TokenType.GroupDivider, "["); //skip open square bracket 160 | 161 | while (!tokens.peekSameLine(TokenType.GroupDivider, "]")) { 162 | Expression value = ExpressionReader.readExpression(this); 163 | properties.add(value); 164 | 165 | if (tokens.peekSameLine(TokenType.GroupDivider, ",")) 166 | tokens.next(); 167 | } 168 | 169 | tokens.next(TokenType.GroupDivider, "]"); //skip close square bracket 170 | } 171 | return new ClassExpression(token.getValue(), properties); 172 | } 173 | 174 | // read function invocation: function_name [ argument1, argument2 ] 175 | private FunctionExpression readFunctionInvocation(Token token) { // token contains function name 176 | List arguments = new ArrayList<>(); 177 | if (tokens.peekSameLine(TokenType.GroupDivider, "[")) { 178 | 179 | tokens.next(TokenType.GroupDivider, "["); //skip open square bracket 180 | 181 | while (!tokens.peekSameLine(TokenType.GroupDivider, "]")) { 182 | Expression value = ExpressionReader.readExpression(this); 183 | arguments.add(value); 184 | 185 | if (tokens.peekSameLine(TokenType.GroupDivider, ",")) 186 | tokens.next(); 187 | } 188 | 189 | tokens.next(TokenType.GroupDivider, "]"); //skip close square bracket 190 | } 191 | 192 | return new FunctionExpression(token.getValue(), arguments); 193 | } 194 | 195 | // read array instantiation: array = {1,2,3} 196 | private ArrayExpression readArrayInstance() { 197 | List values = new ArrayList<>(); 198 | 199 | while (!tokens.peekSameLine(TokenType.GroupDivider, "}")) { 200 | Expression value = ExpressionReader.readExpression(this); 201 | values.add(value); 202 | 203 | if (tokens.peekSameLine(TokenType.GroupDivider, ",")) 204 | tokens.next(); 205 | } 206 | 207 | tokens.next(TokenType.GroupDivider, "}"); //skip close square bracket 208 | 209 | return new ArrayExpression(values); 210 | } 211 | 212 | // read array value: array{index} 213 | private ArrayValueOperator readArrayValue(Token token) { 214 | VariableExpression array = new VariableExpression(token.getValue()); 215 | tokens.next(TokenType.GroupDivider, "{"); 216 | Expression arrayIndex = ExpressionReader.readExpression(this); 217 | tokens.next(TokenType.GroupDivider, "}"); 218 | 219 | return new ArrayValueOperator(array, arrayIndex); 220 | } 221 | } 222 | 223 | -------------------------------------------------------------------------------- /src/main/java/org/prakarshs/Parser/StatementParser.java: -------------------------------------------------------------------------------- 1 | package org.prakarshs.Parser; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.prakarshs.Constants.ErrorConstants; 6 | import org.prakarshs.Exceptions.SyntaxException; 7 | import org.prakarshs.Syntax.Statements.*; 8 | import org.prakarshs.Syntax.Statements.Loops.*; 9 | import org.prakarshs.Syntax.Expressions.Expression; 10 | import org.prakarshs.Syntax.Expressions.ExpressionReader; 11 | import org.prakarshs.Syntax.Expressions.VariableExpression; 12 | import org.prakarshs.Syntax.Expressions.Operators.OperatorExpression; 13 | import org.prakarshs.Syntax.Values.LogicalValue; 14 | 15 | import org.prakarshs.Tokens.Token; 16 | import org.prakarshs.Tokens.TokenType; 17 | import org.prakarshs.Tokens.TokensStack; 18 | import org.prakarshs.Context.definition.*; 19 | 20 | import java.util.*; 21 | 22 | @RequiredArgsConstructor 23 | @Getter 24 | public class StatementParser { 25 | private final TokensStack tokens; 26 | private final Scanner scanner; 27 | private final CompositeStatement compositeStatement; 28 | 29 | public static void parse(StatementParser parent, CompositeStatement compositeStatement, DefinitionScope definitionScope) { 30 | DefinitionContext.pushScope(definitionScope); 31 | try { 32 | StatementParser parser = new StatementParser(parent.getTokens(), parent.getScanner(), compositeStatement); 33 | while (parser.hasNextStatement()) { 34 | parser.parseExpression(); 35 | } 36 | } finally { 37 | DefinitionContext.endScope(); 38 | } 39 | } 40 | 41 | public static void parse(List tokens, CompositeStatement compositeStatement) { 42 | StatementParser parser = new StatementParser(new TokensStack(tokens), new Scanner(System.in), compositeStatement); 43 | while (parser.hasNextStatement()) { 44 | parser.parseExpression(); 45 | } 46 | } 47 | 48 | private boolean hasNextStatement() { 49 | if (!tokens.hasNext()) 50 | return false; 51 | if (tokens.peek(TokenType.Operator, TokenType.Variable, TokenType.This)) 52 | return true; 53 | if (tokens.peek(TokenType.Keyword)) { 54 | return !tokens.peek(TokenType.Keyword, "yatoh", "warna", "rescue", "ensure", "khatam","biscuit_khao"); 55 | } 56 | return false; 57 | } 58 | 59 | private void parseExpression() { 60 | Token token = tokens.next(TokenType.Keyword, TokenType.Variable, TokenType.This, TokenType.Operator); 61 | switch (token.getType()) { 62 | case Variable: 63 | case Operator: 64 | case This: 65 | parseExpressionStatement(token); 66 | break; 67 | case Keyword: 68 | parseKeywordStatement(token); 69 | break; 70 | default: 71 | String problem = ErrorConstants.SYNTAX_GALAT_HAI; 72 | String solution = String.format(String.format("Statement can't start with the following lexeme `%s`", token)); 73 | System.out.println("Poblem : "+problem); 74 | System.out.println("Solution : "+solution); 75 | throw new SyntaxException(problem,solution); 76 | 77 | } 78 | } 79 | 80 | private void parseExpressionStatement(Token rowToken) { 81 | tokens.back(); // go back to read an expression from the beginning 82 | Expression value = ExpressionReader.readExpression(tokens); 83 | ExpressionStatement statement = new ExpressionStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), value); 84 | compositeStatement.addStatement(statement); 85 | } 86 | 87 | private void parseKeywordStatement(Token token) { 88 | switch (token.getValue()) { 89 | case "dekhiye_baapuji": 90 | parsePrintStatement(token); 91 | break; 92 | case "lijiye_baapuji": 93 | parseInputStatement(token); 94 | break; 95 | case "agar": 96 | parseConditionStatement(token); 97 | break; 98 | case "kilass": 99 | parseClassDefinition(token); 100 | break; 101 | case "kaam": 102 | parseFunctionDefinition(token); 103 | break; 104 | case "bhejo": 105 | parseReturnStatement(token); 106 | break; 107 | case "chai_piyo": 108 | parseLoopStatement(token); 109 | break; 110 | case "break": 111 | parseBreakStatement(token); 112 | break; 113 | case "next": 114 | parseNextStatement(token); 115 | break; 116 | case "assert": 117 | parseAssertStatement(token); 118 | break; 119 | case "raise": 120 | parseRaiseExceptionStatement(token); 121 | break; 122 | case "ishtart": 123 | parseHandleExceptionStatement(token); 124 | break; 125 | default: 126 | String problem = ErrorConstants.SYNTAX_GALAT_HAI; 127 | String solution = String.format(String.format("Failed to parse a keyword: %s", token.getValue())); 128 | System.out.println("Poblem : "+problem); 129 | System.out.println("Solution : "+solution); 130 | throw new SyntaxException(problem,solution); 131 | } 132 | } 133 | 134 | private void parsePrintStatement(Token rowToken) { 135 | Expression expression = ExpressionReader.readExpression(tokens); 136 | PrintStatement statement = new PrintStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), expression); 137 | compositeStatement.addStatement(statement); 138 | } 139 | 140 | private void parseInputStatement(Token rowToken) { 141 | Token variable = tokens.next(TokenType.Variable); 142 | InputStatement statement = new InputStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), variable.getValue(), scanner::nextLine); 143 | compositeStatement.addStatement(statement); 144 | } 145 | 146 | private void parseConditionStatement(Token rowToken) { 147 | tokens.back(); 148 | ConditionStatement conditionStatement = new ConditionStatement(rowToken.getRowNumber(), compositeStatement.getBlockName()); 149 | 150 | while (!tokens.peek(TokenType.Keyword, "khatam")) { 151 | //read condition case 152 | Token type = tokens.next(TokenType.Keyword, "agar", "yatoh", "warna"); 153 | Expression caseCondition; 154 | if (type.getValue().equals("warna")) { 155 | caseCondition = new LogicalValue(true); //else case does not have the condition 156 | } else { 157 | caseCondition = ExpressionReader.readExpression(tokens); 158 | } 159 | 160 | //read case statements 161 | CompositeStatement caseStatement = new CompositeStatement(rowToken.getRowNumber(), compositeStatement.getBlockName()); 162 | DefinitionScope caseScope = DefinitionContext.newScope(); 163 | StatementParser.parse(this, caseStatement, caseScope); 164 | 165 | //add case 166 | conditionStatement.addCase(caseCondition, caseStatement); 167 | } 168 | tokens.next(TokenType.Keyword, "khatam"); 169 | 170 | compositeStatement.addStatement(conditionStatement); 171 | } 172 | 173 | private void parseClassDefinition(Token rowToken) { 174 | // read class details 175 | ClassDetails classDetails = readClassDetails(); 176 | 177 | // read base types 178 | Set baseTypes = new LinkedHashSet<>(); 179 | if (tokens.peek(TokenType.GroupDivider, ":")) { 180 | while (tokens.peek(TokenType.GroupDivider, ":", ",")) { 181 | tokens.next(); 182 | ClassDetails baseClassDetails = readClassDetails(); 183 | baseTypes.add(baseClassDetails); 184 | } 185 | } 186 | 187 | // add class definition 188 | DefinitionScope classScope = DefinitionContext.newScope(); 189 | ClassStatement classStatement = new ClassStatement(rowToken.getRowNumber(), classDetails.getName()); 190 | ClassDefinition classDefinition = new ClassDefinition(classDetails, baseTypes, classStatement, classScope); 191 | DefinitionContext.getScope().addClass(classDefinition); 192 | 193 | //parse class's statements 194 | StatementParser.parse(this, classStatement, classScope); 195 | tokens.next(TokenType.Keyword, "khatam"); 196 | } 197 | 198 | private ClassDetails readClassDetails() { 199 | Token className = tokens.next(TokenType.Variable); 200 | List classArguments = new ArrayList<>(); 201 | if (tokens.peek(TokenType.GroupDivider, "[")) { 202 | tokens.next(); //skip open square bracket 203 | 204 | while (!tokens.peek(TokenType.GroupDivider, "]")) { 205 | Token argumentToken = tokens.next(TokenType.Variable); 206 | classArguments.add(argumentToken.getValue()); 207 | 208 | if (tokens.peek(TokenType.GroupDivider, ",")) 209 | tokens.next(); 210 | } 211 | 212 | tokens.next(TokenType.GroupDivider, "]"); //skip close square bracket 213 | } 214 | return new ClassDetails(className.getValue(), classArguments); 215 | } 216 | 217 | private void parseFunctionDefinition(Token rowToken) { 218 | Token name = tokens.next(TokenType.Variable); 219 | 220 | List arguments = new ArrayList<>(); 221 | 222 | if (tokens.peek(TokenType.GroupDivider, "[")) { 223 | 224 | tokens.next(TokenType.GroupDivider, "["); //skip open square bracket 225 | 226 | while (!tokens.peek(TokenType.GroupDivider, "]")) { 227 | Token argumentToken = tokens.next(TokenType.Variable); 228 | arguments.add(argumentToken.getValue()); 229 | 230 | if (tokens.peek(TokenType.GroupDivider, ",")) 231 | tokens.next(); 232 | } 233 | 234 | tokens.next(TokenType.GroupDivider, "]"); //skip close square bracket 235 | } 236 | 237 | //add function definition 238 | String blockName = name.getValue(); 239 | if (compositeStatement instanceof ClassStatement) { 240 | blockName = compositeStatement.getBlockName() + "#" + blockName; 241 | } 242 | FunctionStatement functionStatement = new FunctionStatement(rowToken.getRowNumber(), blockName); 243 | DefinitionScope functionScope = DefinitionContext.newScope(); 244 | FunctionDetails functionDetails = new FunctionDetails(name.getValue(), arguments); 245 | FunctionDefinition functionDefinition = new FunctionDefinition(functionDetails, functionStatement, functionScope); 246 | DefinitionContext.getScope().addFunction(functionDefinition); 247 | 248 | //parse function statements 249 | StatementParser.parse(this, functionStatement, functionScope); 250 | tokens.next(TokenType.Keyword, "khatam"); 251 | } 252 | 253 | private void parseReturnStatement(Token rowToken) { 254 | Expression expression = ExpressionReader.readExpression(tokens); 255 | ReturnStatement statement = new ReturnStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), expression); 256 | compositeStatement.addStatement(statement); 257 | } 258 | 259 | private void parseLoopStatement(Token rowToken) { 260 | Expression loopExpression = ExpressionReader.readExpression(tokens); 261 | if (loopExpression instanceof OperatorExpression || loopExpression instanceof VariableExpression) { 262 | AbstractLoopStatement loopStatement; 263 | 264 | if (loopExpression instanceof VariableExpression && tokens.peek(TokenType.Keyword, "in")) { 265 | // loop in 266 | VariableExpression variable = (VariableExpression) loopExpression; 267 | tokens.next(TokenType.Keyword, "in"); 268 | Expression bounds = ExpressionReader.readExpression(tokens); 269 | 270 | if (tokens.peek(TokenType.GroupDivider, "..")) { 271 | // loop in .. 272 | tokens.next(TokenType.GroupDivider, ".."); 273 | Expression upperBound = ExpressionReader.readExpression(tokens); 274 | 275 | if (tokens.peek(TokenType.Keyword, "by")) { 276 | // loop in .. by 277 | tokens.next(TokenType.Keyword, "by"); 278 | Expression step = ExpressionReader.readExpression(tokens); 279 | loopStatement = new ForLoopStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), variable, bounds, upperBound, step); 280 | } else { 281 | // use default step 282 | // loop in .. 283 | loopStatement = new ForLoopStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), variable, bounds, upperBound); 284 | } 285 | 286 | } else { 287 | // loop in 288 | loopStatement = new IterableLoopStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), variable, bounds); 289 | } 290 | 291 | } else { 292 | // loop 293 | loopStatement = new WhileLoopStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), loopExpression); 294 | } 295 | 296 | DefinitionScope loopScope = DefinitionContext.newScope(); 297 | StatementParser.parse(this, loopStatement, loopScope); 298 | tokens.next(TokenType.Keyword, "biscuit_khao"); 299 | 300 | compositeStatement.addStatement(loopStatement); 301 | } 302 | 303 | } 304 | 305 | private void parseBreakStatement(Token rowToken) { 306 | BreakStatement statement = new BreakStatement(rowToken.getRowNumber(), compositeStatement.getBlockName()); 307 | compositeStatement.addStatement(statement); 308 | } 309 | 310 | private void parseNextStatement(Token rowToken) { 311 | NextStatement statement = new NextStatement(rowToken.getRowNumber(), compositeStatement.getBlockName()); 312 | compositeStatement.addStatement(statement); 313 | } 314 | 315 | private void parseAssertStatement(Token rowToken) { 316 | Expression expression = ExpressionReader.readExpression(tokens); 317 | AssertStatement statement = new AssertStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), expression); 318 | compositeStatement.addStatement(statement); 319 | } 320 | 321 | private void parseRaiseExceptionStatement(Token rowToken) { 322 | Expression expression = ExpressionReader.readExpression(tokens); 323 | RaiseExceptionStatement statement = new RaiseExceptionStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), expression); 324 | compositeStatement.addStatement(statement); 325 | } 326 | 327 | private void parseHandleExceptionStatement(Token rowToken) { 328 | // read begin block 329 | CompositeStatement beginStatement = new CompositeStatement(rowToken.getRowNumber(), compositeStatement.getBlockName()); 330 | DefinitionScope beginScope = DefinitionContext.newScope(); 331 | StatementParser.parse(this, beginStatement, beginScope); 332 | 333 | // read rescue block 334 | CompositeStatement rescueStatement = null; 335 | String errorVariable = null; 336 | if (tokens.peek(TokenType.Keyword, "rescue")) { 337 | tokens.next(); 338 | 339 | if (tokens.peekSameLine(TokenType.Variable)) { 340 | errorVariable = tokens.next().getValue(); 341 | } 342 | 343 | rescueStatement = new CompositeStatement(rowToken.getRowNumber(), compositeStatement.getBlockName()); 344 | DefinitionScope rescueScope = DefinitionContext.newScope(); 345 | StatementParser.parse(this, rescueStatement, rescueScope); 346 | } 347 | 348 | // read ensure block 349 | CompositeStatement ensureStatement = null; 350 | if (tokens.peek(TokenType.Keyword, "ensure")) { 351 | tokens.next(); 352 | 353 | ensureStatement = new CompositeStatement(rowToken.getRowNumber(), compositeStatement.getBlockName()); 354 | DefinitionScope ensureScope = DefinitionContext.newScope(); 355 | StatementParser.parse(this, ensureStatement, ensureScope); 356 | } 357 | 358 | // skip end keyword 359 | tokens.next(TokenType.Keyword, "khatam"); 360 | 361 | // construct a statement 362 | HandleExceptionStatement statement = new HandleExceptionStatement(rowToken.getRowNumber(), compositeStatement.getBlockName(), 363 | beginStatement, rescueStatement, ensureStatement, errorVariable); 364 | compositeStatement.addStatement(statement); 365 | } 366 | } 367 | --------------------------------------------------------------------------------