diff --git a/main.uzlang b/main.uzlang index 52be175..462b70f 100644 --- a/main.uzlang +++ b/main.uzlang @@ -1,3 +1,11 @@ -ozgaruvchi x -> 5; -ozgaruvchi y -> 10; -chiqar x + y; \ No newline at end of file +ozgaruvchi x -> 10; +ozgaruvchi y -> 20; + +chiqar "Hello, UzLang!"; + +f qoshish(a | b) { + qaytar a + b; +} + +ozgaruvchi son -> qoshish(x | y); +chiqar son; diff --git a/src/Main.kt b/src/Main.kt index ed584a6..f5ba5a8 100644 --- a/src/Main.kt +++ b/src/Main.kt @@ -19,9 +19,13 @@ fun main() { token = lexer.getNextToken() } + println("Tokens: $tokens") // Debug print + val parser = Parser(tokens) val program = parser.parse() + println("Parsed program: $program") // Debug print + val interpreter = Interpreter(program) interpreter.interpret() -} \ No newline at end of file +} diff --git a/src/ast/ASTNode.kt b/src/ast/ASTNode.kt deleted file mode 100644 index be4b696..0000000 --- a/src/ast/ASTNode.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -sealed class ASTNode \ No newline at end of file diff --git a/src/ast/BinaryOperation.kt b/src/ast/BinaryOperation.kt deleted file mode 100644 index 34ca568..0000000 --- a/src/ast/BinaryOperation.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -data class BinaryOperation(val left: Expression, val operator: String, val right: Expression) : Expression() diff --git a/src/ast/Expression.kt b/src/ast/Expression.kt deleted file mode 100644 index 0f11a0b..0000000 --- a/src/ast/Expression.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -sealed class Expression : ASTNode() diff --git a/src/ast/IfStatement.kt b/src/ast/IfStatement.kt deleted file mode 100644 index 3df1155..0000000 --- a/src/ast/IfStatement.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -data class IfStatement(val condition: Expression, val thenBranch: List, val elseBranch: List? = null) : Statement() \ No newline at end of file diff --git a/src/ast/Number.kt b/src/ast/Number.kt deleted file mode 100644 index 89de824..0000000 --- a/src/ast/Number.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -data class Number(val value: Int) : Expression() \ No newline at end of file diff --git a/src/ast/PrintStatement.kt b/src/ast/PrintStatement.kt deleted file mode 100644 index 8293fb5..0000000 --- a/src/ast/PrintStatement.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -data class PrintStatement(val expression: Expression) : Statement() \ No newline at end of file diff --git a/src/ast/Program.kt b/src/ast/Program.kt deleted file mode 100644 index 70cf811..0000000 --- a/src/ast/Program.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -data class Program(val statements: List) : ASTNode() diff --git a/src/ast/Statement.kt b/src/ast/Statement.kt deleted file mode 100644 index 7fb283c..0000000 --- a/src/ast/Statement.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -sealed class Statement : ASTNode() \ No newline at end of file diff --git a/src/ast/Variable.kt b/src/ast/Variable.kt deleted file mode 100644 index 298285c..0000000 --- a/src/ast/Variable.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -data class Variable(val name: String) : Expression() \ No newline at end of file diff --git a/src/ast/VariableDeclaration.kt b/src/ast/VariableDeclaration.kt deleted file mode 100644 index 0bac9f1..0000000 --- a/src/ast/VariableDeclaration.kt +++ /dev/null @@ -1,3 +0,0 @@ -package ast - -data class VariableDeclaration(val name: String, val value: Expression) : Statement() \ No newline at end of file diff --git a/src/interpreter/Interpreter.kt b/src/interpreter/Interpreter.kt index 535b6b8..7496000 100644 --- a/src/interpreter/Interpreter.kt +++ b/src/interpreter/Interpreter.kt @@ -5,35 +5,77 @@ import ast.Number class Interpreter(private val program: Program) { private val variables = mutableMapOf() + private val functions = mutableMapOf) -> Int>() + private var returnValue: Int? = null + + init { + // Define built-in functions here if necessary + functions["qoshish"] = { args -> args[0] + args[1] } + } fun interpret() { - for (statement in program.statements) { - execute(statement) - } + program.statements.forEach { executeStatement(it) } } - private fun execute(statement: Statement) { + private fun executeStatement(statement: Statement) { when (statement) { is VariableDeclaration -> { - val value = evaluate(statement.value) + val value = evaluateExpression(statement.value) variables[statement.name] = value } is PrintStatement -> { - val value = evaluate(statement.expression) + val value = evaluateExpression(statement.expression) println(value) } + is IfStatement -> { + val condition = evaluateExpression(statement.condition) + if (condition != 0) { + executeBlock(statement.ifBranch) + } else if (statement.elseBranch != null) { + executeBlock(statement.elseBranch) + } + } + is FunctionDefinition -> { + functions[statement.name] = { args -> + // Create a new scope for function execution + val previousVariables = variables.toMap() + statement.parameters.forEachIndexed { index, param -> + variables[param] = args[index] + } + executeBlock(statement.body) + // Capture the return value + val result = returnValue ?: 0 + returnValue = null + // Restore previous variable scope + variables.clear() + variables.putAll(previousVariables) + // Return value (if any) + result + } + } + is ReturnStatement -> { + returnValue = evaluateExpression(statement.expression) + } + else -> throw IllegalArgumentException("Unknown statement type: $statement") + } + } - is IfStatement -> TODO() + private fun executeBlock(block: Block) { + block.statements.forEach { + executeStatement(it) + if (returnValue != null) { + return + } } } - private fun evaluate(expression: Expression): Int { + private fun evaluateExpression(expression: Expression): Int { return when (expression) { is Number -> expression.value - is Variable -> variables[expression.name] ?: throw IllegalArgumentException("Undefined variable: ${expression.name}") + is Variable -> variables[expression.name] ?: throw IllegalArgumentException("Unknown variable: ${expression.name}") is BinaryOperation -> { - val left = evaluate(expression.left) - val right = evaluate(expression.right) + val left = evaluateExpression(expression.left) + val right = evaluateExpression(expression.right) when (expression.operator) { "+" -> left + right "-" -> left - right @@ -42,8 +84,19 @@ class Interpreter(private val program: Program) { else -> throw IllegalArgumentException("Unknown operator: ${expression.operator}") } } - - is Number -> TODO() + is FunctionCall -> { + val function = functions[expression.functionName] ?: throw IllegalArgumentException("Unknown function: ${expression.functionName}") + val arguments = expression.arguments.map { evaluateExpression(it) } + function(arguments) + } + is ListExpression -> { + expression.elements.size + } + is StringLiteral -> { + println(expression.value) + 0 + } + else -> throw IllegalArgumentException("Unknown expression type: $expression") } } -} \ No newline at end of file +} diff --git a/src/lexer/Lexer.kt b/src/lexer/Lexer.kt index e8909b4..068d323 100644 --- a/src/lexer/Lexer.kt +++ b/src/lexer/Lexer.kt @@ -5,100 +5,148 @@ class Lexer(private val input: String) { private val keywords = mapOf( "ozgaruvchi" to TokenType.KEYWORD, - "chiqar" to TokenType.KEYWORD + "chiqar" to TokenType.KEYWORD, + "agar" to TokenType.KEYWORD, + "yoki" to TokenType.KEYWORD, + "f" to TokenType.KEYWORD, + "qaytar" to TokenType.KEYWORD, + "Royxat" to TokenType.KEYWORD ) - private fun currentChar(): Char? = input.getOrNull(position) + fun getNextToken(): Token { + while (position < input.length) { + val currentChar = input[position] - private fun advance() { - position++ - } + if (currentChar.isWhitespace()) { + position++ + continue + } - private fun skipWhitespace() { - while (currentChar()?.isWhitespace() == true) { - advance() - } - } + if (currentChar.isDigit()) { + val number = extractNumber() + return Token(TokenType.NUMBER, number) + } - private fun identifier(): Token { - val start = position - while (currentChar()?.isLetterOrDigit() == true) { - advance() + if (currentChar.isLetter()) { + val identifier = extractIdentifier() + val keywordType = keywords[identifier] + return if (keywordType != null) { + Token(keywordType, identifier) + } else { + Token(TokenType.IDENTIFIER, identifier) + } + } + + if (currentChar == '"') { + val stringLiteral = extractStringLiteral() + return Token(TokenType.STRING, stringLiteral) + } + + // Handle symbols + val symbol = when (currentChar) { + '(' -> { + position++ + "(" + } + ')' -> { + position++ + ")" + } + '+' -> { + position++ + "+" + } + '-' -> { + if (input.getOrNull(position + 1) == '>') { + position += 2 + "->" + } else { + position++ + "-" + } + } + '*' -> { + position++ + "*" + } + '/' -> { + position++ + "/" + } + ';' -> { + position++ + ";" + } + '>' -> { + position++ + ">" + } + '{' -> { + position++ + "{" + } + '}' -> { + position++ + "}" + } + '|' -> { + position++ + "|" + } + '\'' -> { + position++ + "\'" + } + '[' -> { + position++ + "[" + } + ']' -> { + position++ + "]" + } + '.' -> { + position++ + "." + } + else -> { + position++ + throw IllegalArgumentException("Unexpected character: $currentChar") + } + } + return Token(TokenType.SYMBOL, symbol) } - val value = input.substring(start, position) - val type = keywords.getOrDefault(value, TokenType.IDENTIFIER) - return Token(type, value) + + return Token(TokenType.EOF, "") } - private fun number(): Token { - val start = position - while (currentChar()?.isDigit() == true) { - advance() + private fun extractStringLiteral(): String { + val start = position + 1 // Skip the opening quotation mark + var end = start + while (end < input.length && input[end] != '"') { + end++ } - val value = input.substring(start, position) - return Token(TokenType.NUMBER, value) + if (end >= input.length) { + throw IllegalArgumentException("Unterminated string literal") + } + val stringLiteral = input.substring(start, end) + position = end + 1 // Move past the closing quotation mark + return stringLiteral } - private fun symbol(): Token { - val current = currentChar() ?: throw IllegalArgumentException("Unexpected end of input") - val next = input.getOrNull(position + 1) - - return when { - current == '-' && next == '>' -> { - advance() - advance() - Token(TokenType.SYMBOL, "->") - } - current == '+' -> { - advance() - Token(TokenType.SYMBOL, "+") - } - current == '-' -> { - advance() - Token(TokenType.SYMBOL, "-") - } - current == '*' -> { - advance() - Token(TokenType.SYMBOL, "*") - } - current == '/' -> { - advance() - Token(TokenType.SYMBOL, "/") - } - current == '(' -> { - advance() - Token(TokenType.SYMBOL, "(") - } - current == ')' -> { - advance() - Token(TokenType.SYMBOL, ")") - } - current == ';' -> { - advance() - Token(TokenType.SYMBOL, ";") - } - else -> throw IllegalArgumentException("Unexpected character: $current") + private fun extractNumber(): String { + val start = position + while (position < input.length && input[position].isDigit()) { + position++ } + return input.substring(start, position) } - fun getNextToken(): Token { - skipWhitespace() - - val current = currentChar() ?: return Token(TokenType.EOF, "") - - return when { - current == '/' && input.getOrNull(position + 1) == '/' -> { - while (currentChar() != '\n' && currentChar() != null) { - advance() - } - getNextToken() - } - current.isLetter() -> identifier() - current.isDigit() -> number() - current == ':' -> symbol() - current == '(' || current == ')' || current == '+' || current == '-' || current == '*' || current == ';' -> symbol() - else -> throw IllegalArgumentException("Unexpected character: $current") + private fun extractIdentifier(): String { + val start = position + while (position < input.length && (input[position].isLetterOrDigit() || input[position] == '_')) { + position++ } + return input.substring(start, position) } - } \ No newline at end of file diff --git a/src/lexer/Token.kt b/src/lexer/Token.kt index 0eacbbd..58c2586 100644 --- a/src/lexer/Token.kt +++ b/src/lexer/Token.kt @@ -1,3 +1,4 @@ package lexer -data class Token(val type: TokenType, val value: String) \ No newline at end of file +// Token.kt +data class Token(val type: TokenType, val value: String) diff --git a/src/lexer/TokenType.kt b/src/lexer/TokenType.kt index d54d470..d189bfb 100644 --- a/src/lexer/TokenType.kt +++ b/src/lexer/TokenType.kt @@ -1,8 +1,10 @@ package lexer enum class TokenType { - KEYWORD, IDENTIFIER, NUMBER, SYMBOL, EOF, COMMENT, - IF, ELSE, FOR, WHILE, FUNCTION, RETURN, - LEFT_BRACE, RIGHT_BRACE, LEFT_BRACKET, RIGHT_BRACKET, - COMMA + KEYWORD, + IDENTIFIER, + NUMBER, + STRING, + SYMBOL, + EOF } \ No newline at end of file diff --git a/src/parser/Parser.kt b/src/parser/Parser.kt index 29000cd..d93dcfd 100644 --- a/src/parser/Parser.kt +++ b/src/parser/Parser.kt @@ -1,6 +1,6 @@ +// parser/Parser.kt package parser -import ast.Variable import ast.* import lexer.Token import lexer.TokenType @@ -16,18 +16,6 @@ class Parser(private val tokens: List) { } } - private fun consume(type: TokenType, value: String? = null, endOfInputAllowed: Boolean = false): Token { - val token = currentToken() - if (token.type == type && (value == null || token.value == value)) { - advance() - return token - } else if (endOfInputAllowed && token.type == TokenType.EOF) { - return token - } - throw IllegalArgumentException("Expected $type with value $value but got ${token.type} with value ${token.value}") - } - - fun parse(): Program { val statements = mutableListOf() while (currentToken().type != TokenType.EOF) { @@ -40,73 +28,176 @@ class Parser(private val tokens: List) { return when (currentToken().value) { "ozgaruvchi" -> parseVariableDeclaration() "chiqar" -> parsePrintStatement() + "agar" -> parseIfStatement() + "f" -> parseFunctionDefinition() + "qaytar" -> parseReturnStatement() else -> throw IllegalArgumentException("Unexpected token: ${currentToken().value}") } } - private fun parseVariableDeclaration(): Statement { - consume(TokenType.KEYWORD, "ozgaruvchi") - val name = consume(TokenType.IDENTIFIER).value - consume(TokenType.SYMBOL, "->") + private fun parseReturnStatement(): ReturnStatement { + advance() // consume "qaytar" + val expression = parseExpression() + if (currentToken().value != ";") { + throw IllegalArgumentException("Expected ';' after return statement") + } + advance() // consume ";" + return ReturnStatement(expression) + } + + private fun parseVariableDeclaration(): VariableDeclaration { + advance() // consume "ozgaruvchi" + val name = currentToken().value + advance() // consume variable name + if (currentToken().value != "->") { + throw IllegalArgumentException("Expected '->' after variable name") + } + advance() // consume "->" val value = parseExpression() - consume(TokenType.SYMBOL, ";", true) // Allow for end of input as well + if (currentToken().value != ";") { + throw IllegalArgumentException("Expected ';' after variable declaration") + } + advance() // consume ";" return VariableDeclaration(name, value) } - private fun parsePrintStatement(): Statement { - consume(TokenType.KEYWORD, "chiqar") + private fun parsePrintStatement(): PrintStatement { + advance() // consume "chiqar" val expression = parseExpression() - consume(TokenType.SYMBOL, ";", true) // Allow for end of input as well + if (currentToken().value != ";") { + throw IllegalArgumentException("Expected ';' after print statement") + } + advance() // consume ";" return PrintStatement(expression) } + private fun parseIfStatement(): IfStatement { + advance() // consume "agar" + if (currentToken().value != "(") { + throw IllegalArgumentException("Expected '(' after 'agar'") + } + advance() // consume "(" + val condition = parseExpression() + if (currentToken().value != ")") { + throw IllegalArgumentException("Expected ')' after condition") + } + advance() // consume ")" + if (currentToken().value != "{") { + throw IllegalArgumentException("Expected '{' after ')'") + } + val ifBranch = parseBlock() + var elseBranch: Block? = null + if (currentToken().value == "yoki") { + advance() // consume "yoki" + elseBranch = parseBlock() + } + return IfStatement(condition, ifBranch, elseBranch) + } + + private fun parseBlock(): Block { + val statements = mutableListOf() + if (currentToken().value != "{") { + throw IllegalArgumentException("Expected '{' to start block") + } + advance() // consume "{" + while (currentToken().value != "}") { + statements.add(parseStatement()) + } + advance() // consume "}" + return Block(statements) + } + + private fun parseFunctionDefinition(): FunctionDefinition { + advance() // consume "f" + val name = currentToken().value + advance() // consume function name + if (currentToken().value != "(") { + throw IllegalArgumentException("Expected '(' after function name") + } + advance() // consume "(" + val parameters = mutableListOf() + while (currentToken().value != ")") { + parameters.add(currentToken().value) + advance() // consume parameter + if (currentToken().value == "|") { + advance() // consume "|" + } + } + advance() // consume ")" + val body = parseBlock() + var returnStatement: ReturnStatement? = null + if (currentToken().value == "qaytar") { + returnStatement = parseReturnStatement() + } + return FunctionDefinition(name, parameters, body, returnStatement) + } private fun parseExpression(): Expression { - var result = parseTerm() - while (currentToken().value in listOf("+", "-")) { - val operator = currentToken().value - advance() - val right = parseTerm() - result = BinaryOperation(result, operator, right) - } - return result + return parseBinaryOperation() } - private fun parseTerm(): Expression { - var result = parseFactor() - while (currentToken().value in listOf("*", "/")) { + private fun parseBinaryOperation(): Expression { + var left = parsePrimary() + while (currentToken().value in listOf("+", "-", "*", "/", ">", "<", "==")) { val operator = currentToken().value - advance() - val right = parseFactor() - result = BinaryOperation(result, operator, right) + advance() // consume operator + val right = parsePrimary() + left = BinaryOperation(left, operator, right) } - return result + return left } - private fun parseFactor(): Expression { + private fun parsePrimary(): Expression { return when (currentToken().type) { TokenType.NUMBER -> { val value = currentToken().value.toInt() - advance() + advance() // consume number Number(value) } TokenType.IDENTIFIER -> { val name = currentToken().value - advance() - Variable(name) - } - TokenType.SYMBOL -> { + advance() // consume identifier if (currentToken().value == "(") { - advance() - val expression = parseExpression() - consume(TokenType.SYMBOL, ")") - expression + advance() // consume "(" + val arguments = mutableListOf() + while (currentToken().value != ")") { + arguments.add(parseExpression()) + if (currentToken().value == "|") { + advance() // consume "|" + } + } + advance() // consume ")" + FunctionCall(name, arguments) } else { - throw IllegalArgumentException("Unexpected symbol: ${currentToken().value}") + Variable(name) + } + } + TokenType.SYMBOL -> { + when (currentToken().value) { + "[" -> parseListExpression() + else -> throw IllegalArgumentException("Unexpected symbol: ${currentToken().value}") } } + TokenType.STRING -> { + val value = currentToken().value + advance() // consume string + StringLiteral(value) + } else -> throw IllegalArgumentException("Unexpected token: ${currentToken().value}") } } -} \ No newline at end of file + + private fun parseListExpression(): ListExpression { + val elements = mutableListOf() + advance() // consume "[" + while (currentToken().value != "]") { + elements.add(parseExpression()) + if (currentToken().value == "|") { + advance() // consume "|" + } + } + advance() // consume "]" + return ListExpression(elements) + } +}