first commit
Some checks failed
Build and test / build (push) Failing after 16s

This commit is contained in:
retoor 2025-01-18 23:15:47 +01:00
commit 8df331445b
34 changed files with 5255073 additions and 0 deletions

192
.clang-format Normal file
View File

@ -0,0 +1,192 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: BinPack
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

View File

@ -0,0 +1,32 @@
name: Build and test
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
working-directory: ${{github.workspace}}
run: make build
- name: Test all
working-directory: ${{github.workspace}}
run: make test
- name: Bench
working-directory: ${{github.workspace}}
run: make big

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
bin
.vscode
dobre
buffer
*.zip
.history

1
3rdparty/rlib.h vendored Symbolic link
View File

@ -0,0 +1 @@
/usr/include/rlib.h

75
Makefile Normal file
View File

@ -0,0 +1,75 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -Wpedantic -I./3rdparty -isystem ./3rdparty
SRC = ./src/
BIN = ./bin/
BUILD_CMD = $(CC) $(CFLAGS) $(SRC)main.c -o dobre
all: test build_all run
unit_test: build_fast buffer lexer parser dict
script_test: build_fast
-./bin/dobre ./tests/parser/double_class_declaration.dob
./bin/dobre ./tests/parser/assignment.dob
-./bin/dobre ./tests/parser/double_extend_error.dob
-./bin/dobre ./tests/parser/declare_unknown_type.dob
-./bin/dobre ./tests/parser/while.dob
./bin/dobre ./tests/parser/for.dob
./bin/dobre ./tests/parser/operators.dob
./bin/dobre ./tests/parser/declare_function.dob
test: script_test unit_test
build: ensure_bin
$(BUILD_CMD) -o dobre -Ofast
cp dobre ./bin/dobre
build_all: build
$(BUILD_CMD) -o $(BIN)dobre_c99 -std=c99
$(BUILD_CMD) -o $(BIN)dobre_gnu99 -std=gnu99
$(BUILD_CMD) -o $(BIN)dobre_c11 -std=c11
$(BUILD_CMD) -o $(BIN)dobre_gnu11 -std=gnu11
$(BUILD_CMD) -o $(BIN)dobre_c17 -std=c17
$(BUILD_CMD) -o $(BIN)dobre_gnu17 -std=gnu17
$(BUILD_CMD) -o $(BIN)dobre_c2x -std=c2x
$(BUILD_CMD) -o $(BIN)dobre_gnu2x -std=gnu2x
build_fast:
$(CC) $(SRC)main.c -o dobre -Werror -std=c17
cp dobre ./bin/dobre
run:
./bin/dobre ./scripts/valgrind.dob
format:
@clang-format -i $(SRC)*.h $(SRC)*.c
@echo "Formatted source code."
valgrind: build
valgrind --leak-check=full -s ./bin/dobre ./scripts/valgrind.dob
ensure_bin:
@mkdir ./bin 2> /dev/null | true
buffer: ensure_bin
$(CC) $(CFLAGS) $(SRC)buffer.c -o ./bin/buffer
./bin/buffer
lexer: ensure_bin
$(CC) $(CFLAGS) $(SRC)lexer.c -o ./bin/lexer
./bin/lexer
parser: ensure_bin
$(CC) $(CFLAGS) $(SRC)parser.c -o ./bin/parser
./bin/parser
dict: ensure_bin
$(CC) $(CFLAGS) $(SRC)dict.c -o ./bin/dict
./bin/dict
big.disabled: ensure_bin
$(CC) $(CFLAGS) $(SRC)big.c -o ./bin/big
./bin/big

39
README.md Normal file
View File

@ -0,0 +1,39 @@
# Dobre - general purpose language
## Usage
### Syntax example
```
class A {}
class B(A){
A a = 0
}
B *b = 1
```
### Compliation
Run `make build`
### Tests
Run `make test`
### Run custom file
Execute `./bin/dobre [file]`
## Parser
### Statistics
1841408 lines and 16572616 tokens
- Lines per second: 170748.984375
- Time; 10.78s
### Features
- declare class optionally classes to extend. These are two different notations.
- prevent double declaration of classes.
- prevent double declaration of classes to extend.
- declare variable with native types (char, int, bool).
- declare variable with new specified classes.
- prevent declaration of variable with non existing type or class.
- declare variable assign.
### Todo
- assignment to boolean (crashes).
- assignment to symbol (crashes).

5252133
scripts/big.dob Normal file

File diff suppressed because it is too large Load Diff

27
scripts/script.dob Normal file
View File

@ -0,0 +1,27 @@
class Base (){
void _value = 1336
}
void value_between = 1337
class String (Base){
void another_check = 1338
}
class Integer(Base) {}
class Boolean (Base) {}
class Token (String a, String b, String c) {}
class Trip2 () {
int inside_class_without_extends = 1
}
//moooi
void ** pony = 5
void ** brony = 5
Boolean mytest = 1335
// END FILE

6
scripts/valgrind.dob Normal file
View File

@ -0,0 +1,6 @@
char a = 2
char a = 2
char a = 2
char a = 2
char a = 2
char a = 2

112
src/array.h Normal file
View File

@ -0,0 +1,112 @@
#ifndef ARRAY_H
#define ARRAY_H
#include "buffer.h"
#include "string.h"
#include <stdlib.h>
#include <string.h>
typedef enum array_item_type_t {
ARRAY_ITEM_TYPE_POINTER,
ARRAY_ITEM_TYPE_STRING
} array_item_type_t;
typedef struct array_item_t {
void *value;
bool free;
array_item_type_t type;
} array_item_t;
typedef struct array_t {
array_item_t **data;
unsigned int count;
unsigned int size;
} array_t;
array_t *array_new() {
array_t *a = (array_t *)malloc(sizeof(array_t));
a->data = NULL;
a->count = 0;
a->size = 0;
return a;
}
void array_delete(array_t *a) {
for (unsigned int i = 0; i < a->count; i++) {
if (a->data[i]->free) {
free(a->data[i]->value);
}
free(a->data[i]);
}
// if(a->data)
// free(a->data);
free(a);
}
array_item_t *array_item_new(array_item_type_t type, void *value, bool pfree) {
array_item_t *t = (array_item_t *)malloc(sizeof(array_item_t));
t->value = value;
t->free = pfree;
t->type = type;
return t;
}
void array_push_item(array_t *a, array_item_t *item) {
if (a->count >= a->size) {
a->data = (array_item_t **)realloc(
a->data, a->size * sizeof(array_item_t *) + 1);
a->data[a->size] = item;
a->size += 1;
}
a->count++;
}
bool array_string_exists(array_t *a, char *data) {
if (data == NULL)
return true;
for (unsigned int i = 0; i < a->count; i++) {
if (a->data[i]->type == ARRAY_ITEM_TYPE_STRING &&
!strcmp((char *)a->data[i]->value, data)) {
return true;
}
}
return false;
}
bool array_pointer_exists(array_t *a, void *value) {
if (value == NULL)
return true;
for (unsigned int i = 0; i < a->count; i++) {
if (a->data[i]->value == value) {
return true;
}
}
return false;
}
bool array_push_pointer(array_t *a, void *value, bool pfree) {
if (array_pointer_exists(a, value))
return false;
array_item_t *item = array_item_new(ARRAY_ITEM_TYPE_POINTER, value, pfree);
array_push_item(a, item);
return true;
}
bool array_push_string(array_t *a, char *data) {
if (!data || !*data)
return false;
if (array_string_exists(a, data))
return false;
array_item_t *item =
array_item_new(ARRAY_ITEM_TYPE_STRING, strdup(data), true);
array_push_item(a, item);
return true;
}
char *array_to_option_string(array_t *a) {
buffer_t *buffer = buffer_new(NULL, 0);
for (unsigned int i = 0; i < a->count; i++) {
if (a->data[i]->type == ARRAY_ITEM_TYPE_STRING) {
buffer_write(buffer, (char *)a->data[i]->value,
strlen((char *)a->data[i]->value));
}
if (i != a->count - 1)
buffer_push(buffer, '|');
}
return buffer_to_str(buffer);
}
#endif

604
src/ast.h Normal file
View File

@ -0,0 +1,604 @@
#ifndef AST_H
#define AST_H
#include "array.h"
#include "dict.h"
#include "dobre.h"
#include "string.h"
#include <stdbool.h>
typedef enum ast_type_t {
AST_NODE,
AST_VALUE,
AST_CLASS_DECLARATION,
AST_VAR_DECLARATION,
AST_ASSIGNMENT,
AST_ARRAY,
AST_WHILE,
AST_FOR,
AST_EQUAL,
AST_LT,
AST_LTE,
AST_GT,
AST_GTE,
AST_NOT,
AST_NOT_EQUAL,
AST_FUNCTION_DECLARATION,
AST_FUNCTION_CALL
} ast_type_t;
typedef struct ast_t {
ast_type_t type;
struct ast_t **children;
unsigned int children_count;
} ast_t;
typedef struct ast_value_t {
ast_t node;
char *value;
char *type;
} ast_value_t;
typedef struct ast_equal_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_equal_t;
typedef struct ast_lt_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_lt_t;
typedef struct ast_lte_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_lte_t;
typedef struct ast_gt_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_gt_t;
typedef struct ast_gte_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_gte_t;
typedef struct ast_not_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_not_t;
typedef struct ast_not_equal_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_not_equal_t;
typedef struct ast_for_t {
ast_t node;
ast_t *start;
ast_t *end;
ast_t *statement;
ast_t *closure;
} ast_for_t;
typedef struct ast_class_definition_t {
ast_t node;
char *name;
ast_t *body;
array_t *extends;
} ast_class_definition_t;
typedef struct ast_function_declaration_t {
ast_t node;
char *name;
char * type;
ast_t *body;
dict_t *params;
unsigned int stars;
} ast_function_declaration_t;
typedef struct ast_function_call_t {
ast_t node;
char *name;
dict_t *params;
unsigned int stars;
} ast_function_call_t;
typedef struct ast_var_declaration_t {
ast_t node;
char *type;
char *name;
unsigned int stars;
} ast_var_declaration_t;
typedef struct ast_assignment_t {
ast_t node;
char *name;
ast_value_t *value;
} ast_assignment_t;
typedef struct ast_while_t {
ast_t node;
ast_t *statement;
ast_t *closure;
} ast_while_t;
ast_t *ast_new(char *type);
void ast_delete(ast_t *node);
ast_value_t *ast_value_new(char *value, char *type);
ast_class_definition_t *ast_class_definition_new(char *name);
void ast_class_definition_delete(ast_class_definition_t *definition);
ast_var_declaration_t *ast_var_declaration_new(char *type, char *name);
void ast_var_declaration_delete(ast_var_declaration_t *declaration);
ast_assignment_t *ast_assignment_new(char *name, ast_value_t *value);
void ast_assignment_delete(ast_assignment_t *assignment);
void ast_dump(ast_t *node);
void ast_init(ast_t *ast) {
ast->children = NULL;
ast->children_count = 0;
ast->type = AST_NODE;
}
void ast_value_delete(ast_value_t *value);
void ast_class_definition_delete(ast_class_definition_t *definition);
void ast_var_declaration_delete(ast_var_declaration_t *declaration);
void ast_assignment_delete(ast_assignment_t *assignment);
void ast_while_delete(ast_while_t *while_fn);
void ast_for_delete(ast_for_t *for_fn);
void ast_equal_delete(ast_equal_t *ast);
void ast_gt_delete(ast_gt_t *ast);
void ast_gte_delete(ast_gte_t *ast);
void ast_lt_delete(ast_lt_t *ast);
void ast_lte_delete(ast_lte_t *ast);
void ast_not_delete(ast_not_t *ast);
void ast_not_equal_delete(ast_not_equal_t *ast);
void ast_function_declaration_delete(ast_function_declaration_t * ast);
void ast_function_call_delete(ast_function_call_t * ast);
void ast_delete(ast_t *node) {
ast_dump(node);
ast_t *child = node;
if (child->type == AST_VALUE)
ast_value_delete((ast_value_t *)child);
else if (child->type == AST_CLASS_DECLARATION)
ast_class_definition_delete((ast_class_definition_t *)child);
else if (child->type == AST_VAR_DECLARATION)
ast_var_declaration_delete((ast_var_declaration_t *)child);
else if (child->type == AST_ASSIGNMENT)
ast_assignment_delete((ast_assignment_t *)child);
else if (child->type == AST_WHILE) {
ast_while_delete((ast_while_t *)child);
} else if (child->type == AST_FOR) {
ast_for_delete((ast_for_t *)child);
} else if (child->type == AST_EQUAL) {
ast_equal_delete((ast_equal_t *)child);
} else if (child->type == AST_LT) {
ast_lt_delete((ast_lt_t *)child);
} else if (child->type == AST_LTE) {
ast_lte_delete((ast_lte_t *)child);
} else if (child->type == AST_GT) {
ast_gt_delete((ast_gt_t *)child);
} else if (child->type == AST_GTE) {
ast_gte_delete((ast_gte_t *)child);
} else if (child->type == AST_NOT_EQUAL) {
ast_not_equal_delete((ast_not_equal_t *)child);
} else if (child->type == AST_NOT) {
ast_not_delete((ast_not_t *)child);
} else if(child->type == AST_FUNCTION_DECLARATION){
ast_function_declaration_delete((ast_function_declaration_t *)child);
} else if(child->type == AST_FUNCTION_CALL){
ast_function_call_delete((ast_function_call_t *)child);
}
for (unsigned int i = 0; i < child->children_count; i++)
ast_delete(child->children[i]);
free(child);
}
void ast_add_child(ast_t *parent, ast_t *child) {
parent->children = (ast_t **)realloc(
parent->children, sizeof(ast_t *) * (parent->children_count + 1));
parent->children[parent->children_count] = child;
parent->children_count++;
}
void ast_value_delete(ast_value_t *value) {
printf("Free value %s of type %s.\n", value->value, value->type);
if (value->value)
free(value->value);
if (value->type)
free(value->type);
}
void ast_value_dump(ast_value_t *value);
void ast_class_definition_dump(ast_class_definition_t *definition);
void ast_var_declaration_dump(ast_var_declaration_t *declaration);
void ast_assignment_dump(ast_assignment_t *assignment);
void ast_while_dump(ast_while_t *while_fn);
void ast_for_dump(ast_for_t *for_fn);
void ast_equal_dump(ast_equal_t *ast);
void ast_lt_dump(ast_lt_t *ast);
void ast_lte_dump(ast_lte_t *ast);
void ast_gt_dump(ast_gt_t *ast);
void ast_gte_dump(ast_gte_t *ast);
void ast_function_declaration_dump(ast_function_declaration_t * ast);
void ast_function_call_dump(ast_function_call_t * ast);
void ast_dump(ast_t *node) {
if (!node)
return;
if (node->type == AST_VALUE) {
ast_value_dump((ast_value_t *)node);
} else if (node->type == AST_CLASS_DECLARATION) {
ast_class_definition_dump((ast_class_definition_t *)node);
} else if (node->type == AST_VAR_DECLARATION) {
ast_var_declaration_dump((ast_var_declaration_t *)node);
} else if (node->type == AST_ASSIGNMENT) {
ast_assignment_dump((ast_assignment_t *)node);
} else if (node->type == AST_WHILE) {
ast_while_dump((ast_while_t *)node);
} else if (node->type == AST_FOR) {
ast_for_dump((ast_for_t *)node);
} else if (node->type == AST_EQUAL) {
ast_equal_dump((ast_equal_t *)node);
} else if (node->type == AST_LT) {
ast_lt_dump((ast_lt_t *)node);
} else if (node->type == AST_LTE) {
ast_lte_dump((ast_lte_t *)node);
} else if (node->type == AST_GT) {
ast_gt_dump((ast_gt_t *)node);
} else if (node->type == AST_GTE) {
ast_gte_dump((ast_gte_t *)node);
}else if(node->type == AST_FUNCTION_DECLARATION){
ast_function_declaration_dump((ast_function_declaration_t *)node);
}
}
ast_value_t *ast_value_new(char *value, char *type) {
ast_value_t *result = (ast_value_t *)malloc(sizeof(ast_value_t));
ast_init(&result->node);
result->node.type = AST_VALUE;
result->type = strdup(type);
result->value = value ? strdup(value) : NULL;
return result;
}
void ast_value_dump(ast_value_t *value) {
printf("Type: value. Value: %s. Type: %s\n", value->value, value->type);
}
ast_class_definition_t *ast_class_definition_new(char *name) {
ast_class_definition_t *result =
(ast_class_definition_t *)malloc(sizeof(ast_class_definition_t));
ast_init(&result->node);
result->node.type = AST_CLASS_DECLARATION;
result->name = strdup(name);
result->body = NULL;
result->extends = NULL;
return result;
}
void ast_class_definition_delete(ast_class_definition_t *definition) {
printf("Free class %s\n", definition->name);
if (definition->extends) {
array_delete(definition->extends);
}
if (definition->name)
free(definition->name);
if (definition->body) {
ast_delete(definition->body);
}
}
void ast_class_definition_dump(ast_class_definition_t *definition) {
printf("Defined class %s", definition->name);
printf("(");
if (definition->extends && definition->extends->count > 0) {
for (unsigned int i = 0; i < definition->extends->count; i++) {
if (definition->extends->data[i]->value) {
printf("%s", (char *)definition->extends->data[i]->value);
}
if (i != definition->extends->count - 1) {
printf(",");
}
}
}
printf(")\n");
}
ast_var_declaration_t *ast_var_declaration_new(char *type, char *name) {
ast_var_declaration_t *result =
(ast_var_declaration_t *)malloc(sizeof(ast_var_declaration_t));
ast_init(&result->node);
result->node.type = AST_VAR_DECLARATION;
result->type = strdup(type);
result->name = strdup(name);
result->stars = 0;
return result;
}
void ast_var_declaration_dump(ast_var_declaration_t *declaration) {
printf("Declared variable %s with type %s", declaration->name,
declaration->type);
for (unsigned int i = 0; i < declaration->stars; i++) {
printf("*");
}
printf("\n");
}
void ast_var_declaration_delete(ast_var_declaration_t *declaration) {
printf("Free %s %s.\n", declaration->type, declaration->name);
if (declaration->type)
free(declaration->type);
if (declaration->name)
free(declaration->name);
}
void ast_assignment_dump(ast_assignment_t *assignment) {
printf("Assigned %s with \"%s\".\n", assignment->name,
assignment->value->value);
}
ast_assignment_t *ast_assignment_new(char *name, ast_value_t *value) {
ast_assignment_t *result =
(ast_assignment_t *)malloc(sizeof(ast_assignment_t));
ast_init(&result->node);
result->node.type = AST_ASSIGNMENT;
result->name = strdup(name);
result->value = value;
return result;
}
void ast_assignment_delete(ast_assignment_t *assignment) {
printf("Free assignment %s.\n", assignment->name);
free(assignment->name);
ast_value_delete(assignment->value);
}
ast_t *ast_closure_new() {
ast_t *closure = (ast_t *)malloc(sizeof(ast_t));
ast_init(closure);
return closure;
}
/*
void ast_closure_delete(ast_t *closure) { return; }
*/
ast_t *ast_array_new() {
ast_t *array = (ast_t *)malloc(sizeof(ast_t));
ast_init(array);
return array;
}
void ast_while_dump(ast_while_t *while_fn) {
printf("While (\n");
ast_dump(while_fn->statement);
printf(")\n{\n");
ast_dump(while_fn->closure);
printf("}\n");
}
ast_while_t *ast_while_new(ast_t *statement, ast_t *closure) {
ast_while_t *result = (ast_while_t *)malloc(sizeof(ast_while_t));
ast_init(&result->node);
result->node.type = AST_WHILE;
result->statement = statement;
result->closure = closure;
return result;
}
void ast_while_delete(ast_while_t *while_fn) {
printf("Free while.\n");
ast_delete(while_fn->statement);
ast_delete(while_fn->closure);
}
void ast_for_dump(ast_for_t *for_fn) {
printf("for (\n");
ast_dump(for_fn->start);
ast_dump(for_fn->end);
ast_dump(for_fn->statement);
printf(")\n{\n");
ast_dump(for_fn->closure);
printf("}\n");
}
ast_for_t *ast_for_new(ast_t *start, ast_t *end, ast_t *statement,
ast_t *closure) {
ast_for_t *result = (ast_for_t *)malloc(sizeof(ast_for_t));
ast_init(&result->node);
result->node.type = AST_FOR;
result->start = start;
result->end = end;
result->statement = statement;
result->closure = closure;
return result;
}
void ast_for_delete(ast_for_t *for_fn) {
printf("Free for.\n");
ast_delete(for_fn->statement);
ast_delete(for_fn->start);
ast_delete(for_fn->end);
ast_delete(for_fn->closure);
}
ast_equal_t *ast_equal_new(char *name, ast_value_t *value) {
ast_equal_t *ast = (ast_equal_t *)malloc(sizeof(ast_equal_t));
ast_init(&ast->node);
ast->node.type = AST_EQUAL;
ast->name = strdup(name);
ast->value = value;
return ast;
}
void ast_equal_dump(ast_equal_t *ast) {
printf("Equal comparison %s with \"%s\".\n", ast->name,
ast->value->value);
}
void ast_equal_delete(ast_equal_t *ast) {
printf("Free equal comparison %s.\n", ast->name);
free(ast->name);
ast_value_delete(ast->value);
}
ast_lt_t *ast_lt_new(char *name, ast_value_t *value) {
ast_lt_t *ast = (ast_lt_t *)malloc(sizeof(ast_lt_t));
ast_init(&ast->node);
ast->node.type = AST_LT;
ast->name = strdup(name);
ast->value = value;
return ast;
}
void ast_lt_dump(ast_lt_t *ast) {
printf("Lt comparison %s with \"%s\".\n", ast->name,
ast->value->value);
}
void ast_lt_delete(ast_lt_t *ast) {
printf("Free lt comparison %s.\n", ast->name);
free(ast->name);
ast_value_delete(ast->value);
}
ast_lte_t *ast_lte_new(char *name, ast_value_t *value) {
ast_lte_t *ast = (ast_lte_t *)malloc(sizeof(ast_lte_t));
ast_init(&ast->node);
ast->node.type = AST_LTE;
ast->name = strdup(name);
ast->value = value;
return ast;
}
void ast_lte_dump(ast_lte_t *ast) {
printf("Lte comparison %s with \"%s\".\n", ast->name,
ast->value->value);
}
void ast_lte_delete(ast_lte_t *ast) {
printf("Free lte comparison %s.\n", ast->name);
free(ast->name);
ast_value_delete(ast->value);
}
ast_gt_t *ast_gt_new(char *name, ast_value_t *value) {
ast_gt_t *ast = (ast_gt_t *)malloc(sizeof(ast_gt_t));
ast_init(&ast->node);
ast->node.type = AST_GT;
ast->name = strdup(name);
ast->value = value;
return ast;
}
void ast_gt_dump(ast_gt_t *ast) {
printf("Gt comparison %s with \"%s\".\n", ast->name,
ast->value->value);
}
void ast_gt_delete(ast_gt_t *ast) {
printf("Free gt comparison %s.\n", ast->name);
free(ast->name);
ast_value_delete(ast->value);
}
ast_gte_t *ast_gte_new(char *name, ast_value_t *value) {
ast_gte_t *ast = (ast_gte_t *)malloc(sizeof(ast_gte_t));
ast_init(&ast->node);
ast->node.type = AST_GTE;
ast->name = strdup(name);
ast->value = value;
return ast;
}
void ast_gte_dump(ast_gte_t *ast) {
printf("Gte comparison %s with \"%s\".\n", ast->name,
ast->value->value);
}
void ast_gte_delete(ast_gte_t *ast) {
printf("Free gte comparison %s.\n", ast->name);
free(ast->name);
ast_value_delete(ast->value);
}
ast_not_equal_t *ast_not_equal_new(char *name, ast_value_t *value) {
ast_not_equal_t *ast = (ast_not_equal_t *)malloc(sizeof(ast_not_equal_t));
ast_init(&ast->node);
ast->node.type = AST_NOT_EQUAL;
ast->name = strdup(name);
ast->value = value;
return ast;
}
void ast_not_equal_dump(ast_not_equal_t *ast) {
printf("not_equal comparison %s with \"%s\".\n", ast->name,
ast->value->value);
}
void ast_not_equal_delete(ast_not_equal_t *ast) {
printf("Free not_equal comparison %s.\n", ast->name);
free(ast->name);
ast_value_delete(ast->value);
}
ast_not_t *ast_not_new(char *name, ast_value_t *value) {
ast_not_t *ast = (ast_not_t *)malloc(sizeof(ast_not_t));
ast_init(&ast->node);
ast->node.type = AST_NOT;
ast->name = strdup(name);
ast->value = value;
return ast;
}
void ast_not_dump(ast_not_t *ast) {
printf("not comparison %s with \"%s\".\n", ast->name,
ast->value->value);
}
void ast_not_delete(ast_not_t *ast) {
printf("Free not comparison %s.\n", ast->name);
free(ast->name);
ast_value_delete(ast->value);
}
ast_function_declaration_t *ast_function_declaration_new(char *type, char *name, dict_t * params, ast_t * body) {
ast_function_declaration_t *result =
(ast_function_declaration_t *)calloc(1, sizeof(ast_function_declaration_t));
ast_init(&result->node);
result->node.type = AST_FUNCTION_DECLARATION;
result->name = strdup(name);
result->type = strdup(type);
result->params = params;
result->body = body;
return result;
}
void ast_function_declaration_delete(ast_function_declaration_t *declaration) {
printf("Free class %s\n", declaration->name);
if (declaration->name)
free(declaration->name);
if(declaration->type)
free(declaration->type);
if (declaration->body) {
ast_delete(declaration->body);
}
if(declaration->params){
dict_delete(declaration->params);
}
}
void ast_function_declaration_dump(ast_function_declaration_t *definition) {
printf("Function declaration of %s<%s>", definition->name,definition->type ? definition->type : "NULL");
printf("params: ");
char * dict_string = dict_to_string(definition->params);
printf("%s\n", dict_string);
free(dict_string);
}
ast_function_call_t *ast_function_call_new(char *name, dict_t * params) {
ast_function_call_t *result =
(ast_function_call_t *)calloc(1, sizeof(ast_function_call_t));
ast_init(&result->node);
result->node.type = AST_FUNCTION_CALL;
result->name = strdup(name);
result->params = params;
return result;
}
void ast_function_call_delete(ast_function_call_t *call) {
printf("Free class %s\n", call->name);
if (call->name)
free(call->name);
if(call->params){
dict_delete(call->params);
}
}
void ast_function_call_dump(ast_function_call_t *definition) {
printf("Function call of %s\n", definition->name);
printf("params: ");
char * dict_string = dict_to_string(definition->params);
printf("%s\n", dict_string);
free(dict_string);
}
#endif

28
src/buffer.c Normal file
View File

@ -0,0 +1,28 @@
#include "buffer.h"
int main() {
buffer_t *buff = buffer_new(NULL, 0);
buffer_write(buff, "hello", 5);
assert(buffer_pop(buff) == EOF);
buffer_reset(buff);
assert(buffer_pop(buff) == 'h');
assert(buffer_pop(buff) == 'e');
assert(buffer_pop(buff) == 'l');
assert(buffer_pop(buff) == 'l');
assert(buffer_pop(buff) == 'o');
assert(buffer_pop(buff) == EOF);
buffer_reset(buff);
assert(buff->eof == false);
assert(buff->pos == 0);
assert(buff->size == 5);
assert(!string_match_option("test", "^test"));
assert(string_match_option("test", "test"));
assert(string_match_option("a", "d|e|f|a"));
//", buffer_to_str(buff));
return 0;
}

233
src/buffer.h Normal file
View File

@ -0,0 +1,233 @@
#ifndef BUFFER_H
#define BUFFER_H
#include "dobre.h"
#include <assert.h>
#include <stdbool.h>
typedef struct buffer_t {
char *ptr;
char *data;
size_t size;
size_t pos;
bool eof;
unsigned int line;
unsigned int col;
} buffer_t;
buffer_t *buffer_new(char *data, size_t size);
void buffer_delete(buffer_t *buff);
void buffer_reset(buffer_t *buff);
void buffer_write(buffer_t *buff, const char *data, size_t size);
size_t buffer_push(buffer_t *buff, char);
char buffer_pop(buffer_t *buff);
char *buffer_expect(buffer_t *buff, char *options, char *ignore);
void buffer_set(buffer_t *buff, const char *data, size_t size);
void buffer_unread(buffer_t *buff, unsigned int);
void buffer_unread(buffer_t *buff, unsigned int count) {
if (count > buff->pos) {
return;
}
buff->pos -= count;
buff->ptr -= count;
}
void buffer_set(buffer_t *buff, const char *data, size_t size) {
if (buff->ptr) {
free(buff->ptr);
buff->ptr = NULL;
buff->eof = true;
}
if (size) {
buff->data = (char *)malloc(size);
memcpy(buff->data, data, size);
buff->ptr = buff->data;
buff->eof = false;
}
buff->line = 0;
buff->col = 0;
buff->size = size;
buff->pos = 0;
}
buffer_t *buffer_new(char *data, size_t size) {
buffer_t *buff = (buffer_t *)malloc(sizeof(buffer_t));
if (size) {
buff->data = (char *)malloc(size);
memcpy(buff->data, data, size);
buff->ptr = buff->data;
buff->eof = false;
} else {
buff->ptr = NULL;
buff->eof = true;
buff->data = NULL;
buff->ptr = NULL;
}
buff->line = 0;
buff->col = 0;
buff->size = size;
buff->pos = 0;
return buff;
}
void buffer_delete(buffer_t *buff) {
if (buff->data) {
free(buff->data);
}
free(buff);
}
size_t buffer_push(buffer_t *buff, char c) {
if (buff->pos < buff->size) {
buff->ptr[buff->pos++] = c;
buff->ptr[buff->pos] = 0;
return 1;
}
buff->data = realloc(buff->data, buff->size + 2);
buff->ptr = buff->data;
buff->ptr[buff->pos++] = c;
buff->ptr[buff->pos] = 0;
buff->size++;
return buff->pos;
}
void buffer_write(buffer_t *buff, const char *data, size_t size) {
char *data_ptr = (char *)data;
for (size_t i = 0; i < size; i++) {
buffer_push(buff, data_ptr[i]);
}
}
char buffer_peek(buffer_t *buff) {
char result = EOF;
if (buff->pos != buff->size) {
result = *(buff->ptr);
return result;
}
buff->eof = true;
return EOF;
}
char buffer_pop(buffer_t *buff) {
if (buff->pos && *(buff->ptr - 1) == '\n') {
buff->line++;
buff->col = 0;
} else if (buff->pos) {
buff->col++;
}
char result = EOF;
if (buff->pos < buff->size) {
buff->ptr = buff->data + buff->pos;
result = *buff->ptr;
buff->pos++;
buff->ptr++;
if (buff->pos == buff->size) {
buff->eof = true;
}
return result;
}
buff->eof = true;
return result;
}
void buffer_reset(buffer_t *buff) {
if (buff->ptr)
buff->ptr -= buff->pos;
buff->pos = 0;
buff->eof = false;
}
char *buffer_to_str(buffer_t *buff) {
char *result = buff->data;
buff->data = NULL;
buff->ptr = NULL;
buffer_delete(buff);
return result;
}
char ustrncmp2(const char *s1, const char *s2, size_t n) {
return strncmp((char *)s1, (char *)s2, n);
while (n && *s1 == *s2) {
n--;
s1++;
s2++;
}
return *s1 != *s2;
}
size_t ustrlen2(const char *s) { return strlen((char *)s); }
char *string_match_option(char *buff, char *options) {
char *option = NULL;
char options_cpy[1024] = {0};
strcpy(options_cpy, options);
char *memory = options_cpy;
size_t buff_length = strlen(buff);
while ((option = strtok(option == NULL ? memory : NULL, "|")) != NULL) {
bool reverse = option[0] == '^';
if (reverse) {
option++;
}
size_t option_length = strlen(option);
if (option_length > buff_length) {
continue;
}
if (!strcmp(option, "\\d") && *buff >= '0' && *buff <= '9') {
if (reverse) {
return NULL;
}
return buff;
}
if (buff_length >= 5 && !strcmp(option, "\\b") &&
((!strncmp(buff, "true", 4) || !strncmp(buff, "false", 5)))) {
if (reverse) {
return NULL;
}
return buff;
}
if (!ustrncmp((const unsigned char *)buff, (const unsigned char *)option, option_length)) {
if (reverse) {
return NULL;
}
return buff;
}
}
return NULL;
}
char *buffer_match_option(buffer_t *buff, char *options) {
return string_match_option(buff->ptr, options);
}
char *buffer_expect(buffer_t *buff, char *options, char *ignore) {
while (buff->pos < buff->size) {
if (buffer_match_option(buff, options) != NULL) {
return buff->ptr;
}
printf("MATCIHGG\n");
if (buffer_match_option(buff, ignore)) {
printf("SKIP:%s\n", buff->ptr);
buffer_pop(buff);
continue;
}
break;
}
return NULL;
}
char *buffer_consume(buffer_t *buff, char *options, char *ignore) {
char *result = NULL;
if ((result = buffer_expect(buff, options, ignore)) != NULL) {
printf("HAAA%s\n", result);
buffer_pop(buff);
}
return result;
}
#endif

61
src/class.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef CLASS_H
#define CLASS_H
#include "dobre.h"
#include "string.h"
#include <stdbool.h>
typedef enum class_type_t {
CLASS_VALUE,
CLASS_METHOD,
CLASS_ARRAY,
CLASS_OBJECT,
CLASS_NULL
} class_type_t;
typedef struct class_t {
char *name;
class_type_t type;
size_t attributes_count;
struct class_t *closure;
struct class_t **extends;
struct class_t **attributes;
size_t extends_count;
size_t length;
size_t count;
struct {
unsigned char *string;
long long integer;
double decimal;
bool boolean;
} value;
} class_t;
class_t *class_extend(class_t *self, class_t *parent) {
self->extends_count++;
self->extends = (class_t **)realloc(self->extends, sizeof(class_t *) *
self->extends_count);
self->extends[self->extends_count - 1] = parent;
return self;
}
class_t *class_new(char *name) {
class_t *result = (class_t *)calloc(1, sizeof(class_t));
result->name = strdup(name);
result->length = 0;
result->attributes = NULL;
result->count = 0;
return result;
}
void class_delete(class_t *self) {
free(self->name);
if (self->count) {
for (unsigned int i = 0; i < self->count; i++) {
class_delete(self->attributes[i]);
}
}
free(self);
}
#endif

35
src/dict.c Normal file
View File

@ -0,0 +1,35 @@
#include "dict.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
printf("Testing dict.\n");
dict_t * dict = dict_new();
dict_set_string(dict, "str1", "value1");
assert(!strcmp(dict_get_string(dict,"str1"), "value1"));
assert(dict->count == 1);
dict_remove(dict, "str1");
assert(dict->count == 0);
assert(dict->list == NULL);
assert(dict_get_string(dict,"str1") == NULL);
dict_set_string(dict, "str2", "value2");
assert(!strcmp(dict_get_string(dict,"str2"), "value2"));
assert(dict->count == 1);
dict_remove(dict, "str2");
assert(dict->count == 0);
assert(dict->list == NULL);
return 0;
assert(dict_get_string(dict,"str2") == NULL);
dict_set_string(dict, "str3", "value3");
assert(!strcmp(dict_get_string(dict,"str3"), "value3"));
assert(dict->count == 1);
dict_remove(dict, "str3");
assert(dict->count == 0);
assert(dict->list == NULL);
assert(dict_get_string(dict,"str3") == NULL);
dict_delete(dict);
return 0;
}

170
src/dict.h Normal file
View File

@ -0,0 +1,170 @@
#ifndef DICT_H
#define DICT_H
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define DICT_HASH_SIZE 255
unsigned dict_hash(char *s) {
unsigned int hash;
for (hash = 0; *s != '\0'; s++)
hash = *s + 31 * hash;
return hash % DICT_HASH_SIZE;
}
typedef struct dict_entry_t {
char *key;
void *value;
bool is_managed;
bool is_string;
struct dict_entry_t *next;
struct dict_entry_t *prev;
} dict_entry_t;
typedef struct dict_t {
dict_entry_t *list;
unsigned long count;
dict_entry_t *items[DICT_HASH_SIZE];
} dict_t;
dict_t *dict_new();
dict_entry_t *dict_new_entry();
dict_entry_t *dict_set(dict_t *dict, char *key, void *value);
dict_entry_t *dict_set_managed(dict_t *dict, char *key, void *value);
dict_entry_t *_dict_set(dict_t *dict, bool is_managed, char *key,
void *value);
char *dict_get_string(dict_t *dict, char *key);
dict_entry_t *dict_set_string(dict_t *dict, char *key, char *value);
void dict_remove(dict_t *dict, char *key);
dict_entry_t *dict_get(dict_t *dict, char *key);
dict_entry_t *dict_get(dict_t *dict, char *key) {
return dict->items[dict_hash(key)];
}
char * dict_to_string(dict_t *dict) {
char * dict_string = (char *)calloc(100,sizeof(char));
sprintf(dict_string,"{\n count: %ld\n keys: \n",dict->count);
for(dict_entry_t *entry = dict->list; entry; entry = entry->next) {
char *entry_string = (char *)calloc(100,sizeof(char));
sprintf(entry_string," key: %s value: ",entry->key);
if(entry->is_string){
char value_string[80];
snprintf(value_string,sizeof(value_string),"%s",(char *)entry->value);
strcat(entry_string, "\"");
strcat(entry_string,value_string);
strcat(entry_string, "\"\n");
}else
strcat(entry_string, "*ptr\n");
strcat(dict_string,entry_string);
free(entry_string);
}
strcat(dict_string,"}");
return dict_string;
}
void dict_dump(dict_t *dict) {
printf("%s\n",dict_to_string(dict));
}
void dict_remove(dict_t *dict, char *key) {
dict_entry_t *entry = dict_get(dict, key);
if (!entry) {
printf("HIerooO\n");
return;
}
dict->items[dict_hash(key)] = NULL;
if (entry->next) {
entry->next->prev = entry->prev;
}
if (dict->list == entry) {
dict->list = entry->next;
}
if (entry->prev) {
entry->prev->next = entry->next;
}
if(entry->key)
free(entry->key);
if (entry->value && entry->is_managed) {
free(entry->value);
}
free(entry);
dict->count--;
}
void dict_remove_all(dict_t *dict) {
dict_entry_t * entry = dict->list;
while (entry) {
if(entry->key)
free(entry->key);
if(entry->value && entry->is_managed)
free(entry->value);
dict_entry_t *next = entry->next;
free(entry);
entry = next;
}
dict->count = 0;
dict->list = NULL;
}
dict_entry_t *dict_set_string(dict_t *dict, char *key, char *value) {
char *dup_value = strdup(value);
dict_entry_t * entry = _dict_set(dict, true, key, (void *)dup_value);
entry->is_string = true;
return entry;
}
char *dict_get_string(dict_t *dict, char *key) {
dict_entry_t *entry = dict_get(dict, key);
if (!entry)
{
return NULL;
}
return entry->value;
}
dict_entry_t *_dict_set(dict_t *dict, bool is_managed, char *key,
void *value) {
dict_entry_t *entry = dict_get(dict, key);
if (!entry) {
entry = dict_new_entry();
entry->key = strdup(key);
entry->next = dict->list;
dict->list = entry;
dict->items[dict_hash(key)] = entry;
dict->count++;
} else {
if (entry->value && entry->is_managed) {
free(entry->value);
}
}
entry->is_string = false;
entry->is_managed = is_managed;
entry->value = value;
return entry;
}
dict_entry_t *dict_set(dict_t *dict, char *key, void *value) {
return _dict_set(dict, false, key, value);
}
dict_entry_t *dict_set_managed(dict_t *dict, char *key, void *value) {
return _dict_set(dict, true, key, value);
}
dict_entry_t *dict_new_entry() {
dict_entry_t *entry = (dict_entry_t *)calloc(1, sizeof(dict_entry_t));
entry->key = NULL;
entry->value = NULL;
entry->is_managed = false;
entry->next = NULL;
entry->prev = NULL;
return entry;
}
void dict_delete(dict_t *dict) {
dict_remove_all(dict);
free(dict);
}
dict_t *dict_new() { return (dict_t *)calloc(1, sizeof(dict_t)); }
#endif

26
src/dobre.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef DOBRE_MAIN
#define DOBRE_MAIN
#include <rlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef strdup
char *_dobre_strdup(const char *s) {
if (!s)
return NULL;
char *result;
rmalloc_count++;
rmalloc_alloc_count++;
size_t size = strlen(s) + 1;
while (!(result = (char *)malloc(size))) {
fprintf(stderr, "Warning: strdup failed, trying again.\n");
}
memcpy(result, s, size);
return result;
}
#define strdup _dobre_strdup
#endif
#endif

57
src/lexer.c Normal file
View File

@ -0,0 +1,57 @@
#include <rlib.h>
#include "lexer.h"
char * generate_script(size_t size){
char *small_script = " // comment\n"
" /* multiline comment */\n"
" class Number{}\n"
" class String{}\n"
" class Boolean{}\n"
" Number number1 = -1\n"
" Number number2 = 2\n"
" Number number3 = 3.0\n"
" Number number4 = -3.0\n"
" String string1 = \"\"\n"
" String string2 = \"2\"\n"
" Boolean bool1 = true\n"
" Boolean bool2 = true\n"
" class Myclass{}\n"
" class MyClass2(MyClass){}\n"
" for(MyClass i = 0 j = 20 k = 40){\n"
" Number number = 55\n"
" }\n";
char * script = (char *)calloc(size + 10000,sizeof(char));
strcpy(script, small_script);
while(strlen(script) * 2 < size + 10000) {
char * script2 = strdup(script);
strcat(script, script2);
free(script2);
}
return script;
}
int main() {
printf("Testing lexer.c\n");
char *script = generate_script(1024*1024*80);
lexer_t *lexer = lexer_new();
nsecs_t time_start = nsecs();
lexer_parse(lexer, script);
nsecs_t time_end = nsecs();
nsecs_t duration = time_end - time_start;
printf("Size: %f\n", (double)strlen(script) / (1024 * 1024));
printf("Lines per second: %f\n",
((float)lexer->lines) / (duration / 1000000000.0f));
printf("Lines: %d\n", lexer->lines);
printf("Duration: %s\n",format_time(duration));
printf("Token count: %zu\n", lexer->count);
lexer_delete(lexer);
printf(rmalloc_stats());
printf("\n");
free(script);
if (rmalloc_count) {
rprintr("MEMORY ERROR\n");
return 0; // 1;
}
return 0;
}

262
src/lexer.h Normal file
View File

@ -0,0 +1,262 @@
#ifndef LEXER_H
#define LEXER_H
#include "buffer.h"
#include "string.h"
#include "token.h"
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
typedef struct lexer_t {
token_t **tokens;
size_t count;
char *source;
buffer_t *buffer;
unsigned int lines;
} lexer_t;
lexer_t *lexer_new() {
lexer_t *result = (lexer_t *)calloc(1, sizeof(lexer_t));
result->count = 0;
result->buffer = NULL;
result->source = NULL;
result->lines = 0;
// result->length = 0;
return result;
}
bool issymbolchar(char c) { return c == '_' || isalnum(c); }
bool isnumberchar(char c) { return c == '.' || isdigit(c); }
char *cdup(char c) {
char *result = (char *)malloc(2);
result[0] = c;
result[1] = 0;
return result;
}
token_t *lexer_next(lexer_t *lexer) {
char c = buffer_pop(lexer->buffer);
if (c == 0)
return NULL;
token_t *token = token_new();
token->line = lexer->buffer->line;
token->col = lexer->buffer->col;
token->index = lexer->buffer->pos;
if (c == '{') {
token->type = TOKEN_BRACE_OPEN;
token->value = cdup(c);
} else if (c == '}') {
token->type = TOKEN_BRACE_CLOSE;
token->value = cdup(c);
} else if (isdigit(c) ||
(c == '-' && isdigit(buffer_peek(lexer->buffer)))) {
token->type = TOKEN_NUMBER;
buffer_t *buffer = buffer_new(NULL, 0);
buffer_push(buffer, c);
unsigned int dot_count = 0;
while (isnumberchar((c = buffer_peek(lexer->buffer)))) {
c = buffer_pop(lexer->buffer);
if (c == '.') {
dot_count++;
if (dot_count > 1)
continue;
}
buffer_push(buffer, c);
}
token->value = buffer_to_str(buffer);
} else if (issymbolchar(c)) {
buffer_t *buffer = buffer_new(NULL, 0);
buffer_push(buffer, c);
while (issymbolchar((c = buffer_peek(lexer->buffer)))) {
c = buffer_pop(lexer->buffer);
buffer_push(buffer, c);
}
token->value = buffer_to_str(buffer);
if (!strcmp(token->value, "while")) {
token->type = TOKEN_WHILE;
} else if (!strcmp(token->value, "for")) {
token->type = TOKEN_FOR;
} else if (!strcmp(token->value, "class")) {
token->type = TOKEN_CLASS;
} else {
token->type = TOKEN_SYMBOL;
}
} else if (c == '"') {
token->type = TOKEN_STRING;
buffer_t *buffer = buffer_new(NULL, 0);
while ((c = buffer_pop(lexer->buffer)) != '"') {
if (c == '\\') {
c = buffer_pop(lexer->buffer);
if (c == 'n')
c = '\n';
else if (c == 't')
c = '\t';
else if (c == 'r')
c = '\r';
else if (c == 'b')
c = '\b';
else if (c == 'f')
c = '\f';
else if (c == 'v')
c = '\v';
else if (c == 'a')
c = '\a';
}
buffer_push(buffer, c);
}
token->value = buffer_to_str(buffer);
} else if(c == ','){
token->value = cdup(c);
token->type = TOKEN_COMMA;
} else if (c == '#') {
buffer_pop(lexer->buffer);
buffer_t *buffer = buffer_new(NULL, 0);
while ((c = buffer_peek(lexer->buffer)) != '\n') {
c = buffer_pop(lexer->buffer);
buffer_push(buffer, c);
}
token->value = buffer_to_str(buffer);
token->type = TOKEN_MACRO;
} else if (c == '/' && buffer_peek(lexer->buffer) == '/') {
buffer_pop(lexer->buffer);
buffer_t *buffer = buffer_new(NULL, 0);
while ((c = buffer_peek(lexer->buffer)) != '\n') {
c = buffer_pop(lexer->buffer);
buffer_push(buffer, c);
}
token->value = buffer_to_str(buffer);
token->type = TOKEN_COMMENT;
} else if (c == '/' && buffer_peek(lexer->buffer) == '*') {
buffer_pop(lexer->buffer);
buffer_pop(lexer->buffer);
buffer_t *buffer = buffer_new(NULL, 0);
while (true) {
c = buffer_pop(lexer->buffer);
if (c == '*') {
if (buffer_peek(lexer->buffer) == '/') {
buffer_pop(lexer->buffer);
break;
}
}
buffer_push(buffer, c);
}
token->value = buffer_to_str(buffer);
token->type = TOKEN_MULTILINE_COMMENT;
} else if (c == '<') {
if (buffer_peek(lexer->buffer) == '=') {
buffer_pop(lexer->buffer);
token->type = TOKEN_LTE;
token->value = strdup("<=");
} else {
token->type = TOKEN_LT;
token->value = cdup(c);
}
} else if (c == '!') {
if (buffer_peek(lexer->buffer) == '=') {
buffer_pop(lexer->buffer);
token->type = TOKEN_NOT_EQUAL;
token->value = strdup("!=");
} else {
token->type = TOKEN_NOT;
token->value = cdup(c);
}
} else if (c == '>') {
if (buffer_peek(lexer->buffer) == '=') {
buffer_pop(lexer->buffer);
token->type = TOKEN_GTE;
token->value = strdup(">=");
} else {
token->type = TOKEN_GT;
token->value = cdup(c);
}
} else if (c == '=') {
if (buffer_peek(lexer->buffer) == '=') {
buffer_pop(lexer->buffer);
token->type = TOKEN_EQUAL;
token->value = strdup("==");
} else {
token->type = TOKEN_IS;
token->value = cdup(c);
}
} else if (c == '{') {
token->type = TOKEN_BRACE_OPEN;
token->value = cdup(c);
} else if (c == '}') {
token->type = TOKEN_BRACE_CLOSE;
token->value = cdup(c);
} else if (c == '.') {
token->type = TOKEN_DOT;
token->value = cdup(c);
} else if (c == '\n' || c == '\t' || c == ' ') {
token->type = TOKEN_WHITESPACE;
token->value = cdup(c);
} else if (c == '*') {
token->type = TOKEN_STAR;
token->value = cdup(c);
} else if (c == '(') {
token->type = TOKEN_PAREN_OPEN;
token->value = cdup(c);
} else if (c == ')') {
token->type = TOKEN_PAREN_CLOSE;
token->value = cdup(c);
} else if (c == '{') {
token->type = TOKEN_BRACE_OPEN;
token->value = cdup(c);
} else if (c == '}') {
token->type = TOKEN_BRACE_CLOSE;
token->value = cdup(c);
} else {
token->type = TOKEN_UNKNOWN;
token->value = cdup(c);
}
if (token->value)
token->length = strlen(token->value);
return token;
}
void lexer_dump(lexer_t *lexer) {
printf("Token count: %zu\n", lexer->count);
for (unsigned int i = 0; i < lexer->count; i++) {
token_dump(lexer->tokens[i]);
}
}
void lexer_delete(lexer_t *lexer) {
if (lexer->buffer)
buffer_delete(lexer->buffer);
if (lexer->source)
free(lexer->source);
if (lexer->count) {
for (unsigned int i = 0; i < lexer->count; i++) {
token_delete(lexer->tokens[i]);
}
free(lexer->tokens);
}
free(lexer);
}
void lexer_add_token(lexer_t *lexer, token_t *token) {
lexer->tokens =
realloc(lexer->tokens, (lexer->count + 1) * sizeof(token_t *));
lexer->tokens[lexer->count] = token;
lexer->count++;
}
lexer_t *lexer_parse(lexer_t *lexer, char *source) {
lexer->source = strdup(source);
lexer->buffer = buffer_new(source, strlen(source));
token_t *token;
while (lexer->buffer->eof == false && (token = lexer_next(lexer))) {
lexer_add_token(lexer, token);
}
if (lexer->count)
lexer->lines = lexer->tokens[lexer->count - 1]->line + 1;
return lexer;
}
#endif

33
src/main.c Normal file
View File

@ -0,0 +1,33 @@
#define RMALLOC_OVERRIDE 0
#define RMALLOC_DEBUG 1
#include "dobre.h"
#define print rprintb
int printf_dummy(const char *format, ...) {
(void)format;
return 0;
}
#ifdef printf_a
#undef printf
#define printf printf_dummy
#endif
#include "class.h"
#include "lexer.h"
#include "parser.h"
#include "utils.h"
int main(int argc, char *argv[]) {
char *filepath = argc > 1 ? argv[1] : "../scripts/valgrind.dob";
nsecs_t time_start = nsecs();
parse_file(filepath);
nsecs_t time_end = nsecs();
nsecs_t duration = time_end - time_start;
size_t line_count = get_line_count(filepath);
print("Time: %f\n", (float)duration / 1000000000.0f);
print("Lines per second: %f\n",
((float)line_count) / (duration / 1000000000.0f));
print("Time; %s\n", format_time(duration));
print("%s\n", rmalloc_stats());
return 0;
}

70
src/parser.c Normal file
View File

@ -0,0 +1,70 @@
#include <rlib.h>
#define print rprintb
int printf_dummy(const char *format, ...) {
(void)format;
return 0;
}
#ifdef printf
#undef printf
#endif
#define printf printf_dummy
#include "parser.h"
unsigned int parse_only(char *script) {
lexer_t *lexer = lexer_new();
lexer = lexer_parse(lexer, script);
parse(lexer);
unsigned int result = lexer->lines;
lexer_delete(lexer);
return result;
}
void lex_and_parse(char *script) { parse_string(script); }
int main() {
char *script = " // comment\n"
" /* multiline comment */\n"
" class Number{}\n"
" class String{}\n"
" class Boolean{}\n"
" Number number1 = -1\n"
" Number number2 = 2\n"
" Number number3 = 3.0\n"
" Number number4 = -3.0\n"
" String string1 = 5\n"
" String string2 = 4\n"
" Boolean bool1 = 1\n"
" Boolean bool2 = 0\n"
" class Myclass(){}\n"
" class MyClass2(MyClass){}";
lexer_t *lexer = lexer_new();
lexer = lexer_parse(lexer, script);
print("Only lexing:\n");
nsecs_t time_start = nsecs();
parse(lexer);
unsigned int lines = lexer->lines;
unsigned int token_count = lexer->count;
lexer_delete(lexer);
nsecs_t time_end = nsecs();
nsecs_t duration = time_end - time_start;
print("Time: %s\n", format_time(duration));
print("Lines per second: %f\n",
((float)lines) / (duration / 1000000000.0f));
print("Full parsing (lexing+parsing):\n");
time_start = nsecs();
parse_string(script);
time_end = nsecs();
duration = time_end - time_start;
print("Time: %s\n", format_time(duration));
print("Lines per second: %f\n",
((float)lines) / (duration / 1000000000.0f));
print("Lines: %d\n", lines);
print("Token count: %zu\n", token_count);
print("%s\n", rmalloc_stats());
return 0;
}

638
src/parser.h Normal file
View File

@ -0,0 +1,638 @@
#ifndef PARSE_H
#define PARSE_H
#include "dict.h"
#include "array.h"
#include "ast.h"
#include "lexer.h"
#include <stdarg.h>
typedef struct parser_t {
lexer_t *lexer;
ast_t *ast;
token_t *current_token;
token_t *previous_token;
unsigned int token_index;
array_t *class_list;
} parser_t;
ast_t *parse_closure(parser_t *parser, token_type_t type);
token_t *parser_next(parser_t *parser);
token_t *parser_peek(parser_t *parser);
ast_t *parse_class_definition(parser_t *parser);
ast_t *parse_variable_definition(parser_t *parser);
ast_t *parse_statement(parser_t *parser);
ast_t *parse_expression(parser_t *parser);
ast_t *parse_assignment(parser_t *parser);
ast_value_t *parse_value(parser_t *parser);
dict_t * parse_params(parser_t *parser);
unsigned int get_token_index(parser_t *parser, token_t *token) {
for (unsigned i = 0; i < parser->lexer->count; i++) {
if (parser->lexer->tokens[i] == token) {
return i;
}
}
return 0;
}
char *parser_get_line_by_number(parser_t *parser, unsigned int line_number) {
buffer_t *buffer = buffer_new(NULL, 0);
unsigned int first_char_match = 0;
unsigned int last_char_match = 0;
for (unsigned int i = 0; i < parser->lexer->count; i++) {
if (parser->lexer->tokens[i]->line == line_number) {
if (first_char_match == 0) {
first_char_match = parser->lexer->tokens[i]->index;
}
last_char_match = parser->lexer->tokens[i]->index +
parser->lexer->tokens[i]->length;
} else if (parser->lexer->tokens[i]->line > line_number) {
break;
}
}
for (unsigned int i = first_char_match; i < last_char_match; i++) {
buffer_push(buffer, parser->lexer->source[i]);
}
return buffer_to_str(buffer);
}
char *parser_get_source_lines(char *source, unsigned int start_line,
unsigned int end_line) {
buffer_t *buffer = buffer_new(NULL, 0);
size_t source_length = strlen(source);
unsigned int current_line = 0;
for (unsigned int i = 0; i < source_length; i++) {
if (current_line >= start_line) {
buffer_push(buffer, source[i]);
}
if (source[i] == '\n') {
current_line++;
}
if (current_line > end_line && source[i] == '\n') {
break;
}
}
return buffer_to_str(buffer);
}
char *parser_get_source_context(parser_t *parser, token_t *token) {
// int preferred_line_count = 3;
int line_number_start =
token->line; //(((int)token->line - preferred_line_count) > 0) ?
// token->line - preferred_line_count: 0;
char *source = parser_get_source_lines(parser->lexer->source,
line_number_start, token->line);
return source;
}
parser_t *parser_new(lexer_t *lexer) {
parser_t *result = (parser_t *)malloc(sizeof(parser_t));
result->lexer = lexer;
result->ast = NULL;
result->token_index = 0;
result->class_list = array_new();
result->current_token = lexer->count ? lexer->tokens[0] : NULL;
result->previous_token = result->current_token;
while (result->current_token && result->current_token->type < 10) {
parser_next(result);
}
return result;
}
void parser_delete(parser_t *parser) {
array_delete(parser->class_list);
free(parser);
}
token_t *parser_peek(parser_t *parser) {
token_t *token = parser->current_token;
unsigned int token_index = parser->token_index;
if (token_index + 1 < parser->lexer->count) {
token = parser->lexer->tokens[token_index + 1];
token_index++;
while (token->type < 10 && token_index + 1 < parser->lexer->count) {
token = parser->lexer->tokens[token_index + 1];
token_index++;
}
return token;
}
return NULL;
}
token_t *parser_next(parser_t *parser) {
parser->previous_token = parser->current_token;
if (parser->token_index + 1 < parser->lexer->count) {
parser->current_token = parser->lexer->tokens[parser->token_index + 1];
parser->token_index++;
while (parser->current_token->type < 10 &&
parser->token_index + 1 < parser->lexer->count) {
parser->current_token =
parser->lexer->tokens[parser->token_index + 1];
parser->token_index++;
}
return parser->current_token;
} else {
parser->current_token = NULL;
}
return NULL;
}
void parser_raise(parser_t *parser, char *message, ...) {
va_list args;
va_start(args, message);
fprintf(stderr, "\033[31m");
if (parser->current_token) {
fprintf(stderr, "\033[31mError at line %d, column %d: ",
parser->current_token->line + 1,
parser->current_token->col + 1);
vfprintf(stderr, message, args);
fprintf(stderr, "\033[0m");
char *parser_source_context =
parser_get_source_context(parser, parser->current_token);
fprintf(stderr, "%s", parser_source_context);
if(parser_source_context[-1] != '\n'){
fprintf(stderr, "\n");
}
for (unsigned int i = 0; i < parser->current_token->col; i++) {
fprintf(stderr, " ");
}
fprintf(stderr, "\033[31m");
for (unsigned int i = parser->current_token->col;
i < parser->current_token->col + parser->current_token->length;
i++) {
fprintf(stderr, "^");
}
fprintf(stderr, "\033[0m\n");
free(parser_source_context);
}
va_end(args);
}
token_t *parser_expect(parser_t *parser, bool required, ...) {
unsigned int max = 10;
va_list args;
va_start(args, required);
token_t *token = parser->current_token;
if (!token) {
return NULL;
}
int token_type = -1;
bool token_found = false;
for (unsigned int i = 0; i < max; i++) {
token_type = va_arg(args, int);
if (token_type == -1) {
break;
} else if ((int)token->type == token_type) {
token_found = true;
break;
} else if (token_type == TOKEN_UNKNOWN) {
// token_found = true;
break;
}
}
va_end(args);
if (token_type == -1 && required) {
parser_raise(parser, "syntax error. unexpected token: %s\n",
token->value);
exit(2);
}
if (!token_found)
token = NULL;
return token_type == -1 ? NULL : token;
}
token_t *parser_advance(parser_t *parser, bool required, ...) {
va_list args;
va_start(args, required);
token_t *token = NULL;
token = parser_expect(parser, required, args);
if (token)
token = parser_next(parser);
va_end(args);
return token;
}
ast_t *parse_remainder(parser_t *parser) {
parser_next(parser);
return NULL;
}
token_t * _parser_current_token = NULL;
token_t * _parser_previous_token = NULL;
unsigned int _parser_token_index = 0;
void parser_push_state(parser_t * parser){
_parser_current_token = parser->current_token;
_parser_previous_token = parser->previous_token;
_parser_token_index = parser->token_index;
}
void parser_pop_state(parser_t * parser){
parser->current_token = _parser_current_token;
parser->previous_token = _parser_previous_token;
parser->token_index = _parser_token_index;
}
ast_t *parse_operator(parser_t *parser) {
parser_push_state(parser);
parser_next(parser);
if (!parser_expect(parser, false, TOKEN_EQUAL, TOKEN_GT, TOKEN_GTE,
TOKEN_LT, TOKEN_LTE, TOKEN_NOT_EQUAL, -1)) {
parser_pop_state(parser);
return parse_remainder(parser);
}
ast_t *ast = NULL;
token_t *token_identifier = parser->previous_token;
token_t *token_operator = parser->current_token;
parser_next(parser);
ast_value_t *value = parse_value(parser);
if (token_operator->type == TOKEN_EQUAL) {
ast = (ast_t *)ast_equal_new(token_identifier->value, value);
} else if (token_operator->type == TOKEN_GT) {
ast = (ast_t *)ast_gt_new(token_identifier->value, value);
} else if (token_operator->type == TOKEN_GTE) {
ast = (ast_t *)ast_gte_new(token_identifier->value, value);
} else if (token_operator->type == TOKEN_LT) {
ast = (ast_t *)ast_lt_new(token_identifier->value, value);
} else if (token_operator->type == TOKEN_LTE) {
ast = (ast_t *)ast_lte_new(token_identifier->value, value);
} else if (token_operator->type == TOKEN_NOT_EQUAL) {
ast = (ast_t *)ast_not_equal_new(token_identifier->value, value);
}
return (ast_t *)ast;
}
ast_t *parse_assignment(parser_t *parser) {
token_t *token = parser->current_token;
token_t *token_next = parser_peek(parser);
if (token_next->type == TOKEN_IS) {
token = parser_next(parser);
}
if (token->type == TOKEN_IS) {
token_t *token_identifier = parser->previous_token;
parser_next(parser);
ast_value_t *value = parse_value(parser);
ast_assignment_t *assignment =
ast_assignment_new(token_identifier->value, value);
if(parser->current_token)
printf("<<<%s %d>>>\n",token_identifier->value, parser->current_token->type );
return (ast_t *)assignment;
}
return parse_operator(parser);
}
ast_value_t *parse_value(parser_t *parser) {
token_t *token =
parser_expect(parser, true, TOKEN_STRING, TOKEN_NUMBER, TOKEN_BOOLEAN,
TOKEN_SYMBOL, TOKEN_PAREN_OPEN, -1);
if (token->type == TOKEN_PAREN_OPEN) {
return (ast_value_t *)parse_closure(parser, TOKEN_PAREN_OPEN);
}
char *token_type = NULL;
if (token->type == TOKEN_NUMBER) {
token_type = "number";
} else if (token->type == TOKEN_STRING) {
token_type = "string";
} else if (token->type == TOKEN_BOOLEAN) {
token_type = "boolean";
} else if (token->type == TOKEN_BOOLEAN) {
token_type = "symbol";
}
parser_next(parser);
return ast_value_new(token->value, token_type);
}
ast_t *parse_for(parser_t *parser) {
if (!parser_advance(parser, false, TOKEN_FOR, -1)) {
return (ast_t *)parse_expression(parser); // parse_value(parser);
}
parser_advance(parser, true, TOKEN_PAREN_OPEN, -1);
ast_t *start = parse_expression(parser);
ast_t *end = parse_expression(parser);
ast_t *expr = parse_expression(parser);
parser_advance(parser, true, TOKEN_PAREN_CLOSE, -1);
ast_t *closure = parse_closure(parser, TOKEN_BRACE_OPEN);
parser_advance(parser, true, TOKEN_BRACE_CLOSE);
ast_for_t *ast_for = ast_for_new(start, end, expr, closure);
return (ast_t *)ast_for;
}
ast_t *parse_while(parser_t *parser) {
token_t *token = NULL;
if (!(token = parser_advance(parser, false, TOKEN_WHILE, -1))) {
return parse_for(parser);
}
printf("%d:%s\n", token->type, token->value);
ast_t *statement = parse_closure(parser, TOKEN_PAREN_OPEN);
ast_t *closure = parse_closure(parser, TOKEN_BRACE_OPEN);
ast_while_t *ast_while = ast_while_new(statement, closure);
return (ast_t *)ast_while;
}
void parser_dump(parser_t *parser){
unsigned int prev_line = 1337;
unsigned int i = 0;
while(i < parser->lexer->count){
token_t * token = parser->lexer->tokens[i];
if(token->line != prev_line){
prev_line = token->line;
printf("%d:\t", token->line + 1);
}
printf(parser->lexer->tokens[i]->value);
i++;
if(parser->lexer->tokens[i] == parser->current_token){
break;
}
}
printf("\n");
}
ast_t * parse_function_call(parser_t *parser) {
token_t *token = NULL;
if (!(token = parser_expect(parser, false, TOKEN_SYMBOL, -1))) {
return parse_assignment(parser);
}
char * name = token->value;
token = parser_peek(parser);
if(token->type == TOKEN_PAREN_OPEN) {
parser_next(parser);
printf("XXX\n");
dict_t * params = parse_params(parser);
parser_dump(parser);
ast_function_call_t * call = ast_function_call_new(name, params);
printf("XXX %s %d\n",name, parser->current_token->type);
return (ast_t *)call;
}
return parse_assignment(parser);
}
dict_t * parse_params(parser_t *parser) {
parser_expect(parser,true,TOKEN_PAREN_OPEN, -1);
dict_t *params = dict_new();
token_t *token;
while ((token = parser_next(parser))) {
if(token->type == TOKEN_PAREN_CLOSE){
printf("HIERQQ\n");
break;
}
parser_dump(parser);
parser_expect(parser, true, TOKEN_SYMBOL, -1);
ast_t * declaration = (ast_t *)parse_statement(parser);
char * name = token->value;
if(!declaration){
printf("NOTTAA\n");
printf("<%s>\n",name);
}else{
printf("<%s>\n",name);
}
dict_set(params,name,(void *)declaration);
printf("DITT2\n");
token = parser_expect(parser, true, TOKEN_PAREN_CLOSE, TOKEN_COMMA, -1);
printf("DITTT3\n");
if(token->type == TOKEN_PAREN_CLOSE){
break;
}
if(parser->current_token->type != TOKEN_COMMA){
break; // parser_next(parser);
}
}
printf("HIERZ|n\n");
parser_expect(parser, true, TOKEN_PAREN_CLOSE, -1);
parser_next(parser);
return params;
}
ast_t *parse_variable_definition(parser_t *parser) {
if (!parser_expect(parser, false, TOKEN_SYMBOL, -1)) {
return parse_function_call(parser);
}
char *variable_identifiers = "int|char|bool|float|double|void";
token_t *token = parser->current_token;
char *matched_variable_identifier =
string_match_option(token->value, variable_identifiers);
if (!matched_variable_identifier && parser->class_list->count) {
char *user_defined_classes_string =
array_to_option_string(parser->class_list);
matched_variable_identifier =
string_match_option(token->value, user_defined_classes_string);
free(user_defined_classes_string);
}
if (!matched_variable_identifier) {
return parse_function_call(parser);
}
token = parser_peek(parser);
if(token->type != TOKEN_SYMBOL) {
return parse_function_call(parser);
}
char *type = token->value;
unsigned int stars = 0;
while ((token = parser_next(parser)) && token->type == TOKEN_STAR) {
stars++;
}
if (token->type != TOKEN_SYMBOL) {
printf("Syntax error?\n");
}
assert(token->type == TOKEN_SYMBOL);
char *identifier = token->value;
token = parser_next(parser);
if(parser_expect(parser, false, TOKEN_PAREN_OPEN, -1)){
dict_t * params = parse_params(parser);
if(parser_expect(parser, true, TOKEN_BRACE_OPEN, -1)){
ast_t * body = parse_closure(parser, TOKEN_BRACE_OPEN);
ast_function_declaration_t * declaration = ast_function_declaration_new(type, identifier,params,body);
return (ast_t *)declaration;
}
} else if (parser_expect(parser, false, TOKEN_IS, -1)) {
ast_t *assignment = parse_assignment(parser);
ast_var_declaration_t * definition = ast_var_declaration_new(type, identifier);
printf("GGG\n");
definition->stars = stars;
ast_add_child((ast_t *)definition, (ast_t *)assignment);
return (ast_t *)definition;
}
return NULL;
}
ast_t *parse_expression(parser_t *parser) {
ast_t *return_value = parse_variable_definition(parser);
return return_value;
}
ast_t *parse_closure(parser_t *parser, token_type_t open_type) {
token_t *token = parser->current_token;
parser_expect(parser, true, open_type, -1);
int close_type = 0;
if (open_type == TOKEN_PAREN_OPEN) {
close_type = TOKEN_PAREN_CLOSE;
} else if (open_type == TOKEN_BRACE_OPEN) {
close_type = TOKEN_BRACE_CLOSE;
} else if (open_type == TOKEN_UNKNOWN) {
close_type = TOKEN_UNKNOWN;
}
ast_t *closure = ast_closure_new();
if (open_type != TOKEN_UNKNOWN)
token = parser_next(parser);
while (token && (int)token->type != close_type && (int)token->type > 10) {
token_t *token_start = parser->current_token;
ast_t *statement = parse_statement(parser);
if (statement) {
ast_add_child((ast_t *)closure, (ast_t *)statement);
}
token = parser->current_token;
if (token == token_start)
break;
}
parser_expect(parser, true, close_type, -1);
parser_next(parser);
return closure;
}
array_t *parse_class_extends(parser_t *parser,
ast_class_definition_t *definition) {
parser_expect(parser, true, TOKEN_PAREN_OPEN, -1);
array_t *extends = array_new();
parser_next(parser);
while (parser->current_token->type != TOKEN_PAREN_CLOSE) {
if (!array_push_string(extends, parser->current_token->value)) {
parser_raise(parser, "Duplicate extend %s < %s\n", definition->name,
parser->current_token->value);
}
parser_next(parser);
}
parser_expect(parser, true, TOKEN_PAREN_CLOSE, -1);
parser_next(parser);
return extends;
}
ast_t *parse_class_definition(parser_t *parser) {
token_t *token;
if (!(token = parser_expect(parser, false, TOKEN_CLASS, -1))) {
return parse_while(parser);
}
token = parser_next(parser);
if (!array_push_string(parser->class_list, token->value)) {
parser_raise(parser, "Class already defined: %s\n", token->value);
exit(3);
}
ast_class_definition_t *definition = ast_class_definition_new(token->value);
parser_next(parser);
token = parser_expect(parser, true, TOKEN_PAREN_OPEN, TOKEN_BRACE_OPEN, -1);
if (!token) {
parser_raise(parser, "Syntax error. Expected '(' or '{'\n");
exit(2);
}
if (token->type == TOKEN_PAREN_OPEN) {
definition->extends = parse_class_extends(parser, definition);
assert(definition->extends);
parser_expect(parser, true, TOKEN_BRACE_OPEN, -1);
definition->body = parse_closure(parser, TOKEN_BRACE_OPEN);
} else {
definition->body = parse_closure(parser, TOKEN_BRACE_OPEN);
}
assert(definition->body);
return (ast_t *)definition;
}
ast_t *parse_macro(parser_t *parser) {
if (!parser_expect(parser, false, TOKEN_MACRO, -1)) {
return parse_class_definition(parser);
}
char *macro_text = parser->current_token->value;
printf("COMES HERER!!\n");
printf("###%s\n",macro_text);
if (!strcmp(macro_text, "debug")) {
token_t *token_next = parser_peek(parser);
printf("t.line: %d t.col %d t.type: %d t.value:\"%s\"\n",
token_next->line, token_next->col, token_next->value);
}
return NULL;
}
ast_t *parse_statement(parser_t *parser) { return parse_macro(parser); }
ast_t *parse(lexer_t *lexer) {
parser_t *parser = parser_new(lexer);
token_t *token_before = NULL;
token_t *token_after = NULL;
parser->previous_token = parser->current_token;
while (parser->current_token) {
token_before = parser->current_token;
ast_t *result = parse_closure(parser, TOKEN_UNKNOWN);
token_after = parser->current_token;
if (token_before && token_after == token_before) {
parser_raise(parser, "Syntax error. Unexpected '%s'\n",
token_before->value);
printf("debug: in main parser function.\n");
exit(1);
// return NULL;
// exit(0);
// token_dump(token_before);
// parser_next(parser);
}
if (result) {
ast_delete(result);
} else if (parser->current_token) {
// parser_expect(parser, 0, -1);
// exit(3);
// token_dump(parser->current_token);
}
}
parser_delete(parser);
return NULL;
}
char *read_file_contents(char *filename) {
FILE *file = fopen(filename, "r");
if (file == NULL) {
printf("Couldn't open file: %s\n", filename);
exit(1);
}
fseek(file, 0, SEEK_END);
long length = ftell(file);
fseek(file, 0, SEEK_SET);
char *buffer = (char *)malloc(length + 1);
__attribute__((unused)) size_t bytes_read = fread(buffer, length, 1, file);
buffer[length] = 0;
fclose(file);
return buffer;
}
void parse_string(char *script) {
lexer_t *lexer = lexer_new();
lexer = lexer_parse(lexer, script);
parse(lexer);
lexer_delete(lexer);
}
void parse_file(char *filepath) {
char *content = read_file_contents(filepath);
lexer_t *lexer = lexer_new();
lexer = lexer_parse(lexer, content);
parse(lexer);
// lexer_dump(lexer);
print("%d lines and %d tokens\n", lexer->lines, lexer->count);
lexer_delete(lexer);
free(content);
}
#endif

98
src/test.c Normal file
View File

@ -0,0 +1,98 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct test_definition_t {
char *script;
char *expectation;
} test_definition_t;
typedef struct test_t {
test_definition_t definition;
bool valid;
} test_t;
test_t *parse_test(char **content_str) {
char *content = *content_str;
// define start
char *script_start = strstr(content, "```");
if (!script_start) {
return NULL;
}
script_start += 3;
// define end of script
char *script_end = strstr(script_start, "```");
if (!script_end) {
printf("Error, missing end of script.\n");
return NULL;
}
unsigned int script_length = script_end - script_start;
char script[script_length + 1];
script[script_length] = 0;
strncpy(script, script_start, script_length);
script_end += 3;
// define start or expectation
char *expectation_start = strstr(script_end, "```");
if (!expectation_start) {
printf("Error, missing expectation start.\n");
return NULL;
}
expectation_start += 3;
// define end of expectation
char *expectation_end = strstr(expectation_start, "```");
if (!expectation_end) {
printf("Error: missing expectation end.\n");
return NULL;
}
unsigned int expectation_length = expectation_end - expectation_start;
char expectation[expectation_length + 1];
expectation[expectation_length] = 0;
strncpy(expectation, expectation_start, expectation_length);
expectation_end += 3;
// prepare return value
test_t *test = (test_t *)malloc(sizeof(test_t));
test->definition.script = (char *)malloc(script_length + 1);
test->definition.expectation = (char *)malloc(expectation_length + 1);
strcpy(test->definition.script, script);
strcpy(test->definition.expectation, expectation);
test->valid = false;
// update pointer
*content_str = expectation_end;
return test;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: <executable> <*files>");
exit(1);
}
char *execute = argv[1];
stderr = stdout;
FILE *f = popen(execute, "r");
if (!f) {
printf("Couldn't execute %s.\n", execute);
return 1;
}
char data[2048];
fread(data, 1, sizeof(data), f);
printf("%s\n", data);
fclose(f);
char *file_ptr = "```a``````b``````c``````d```";
test_t *test;
while ((test = parse_test(&file_ptr)) != NULL) {
printf("source: <%s> expectation: <%s>\n", test->definition.script,
test->definition.expectation);
}
return 0;
}

64
src/token.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef TOKEN_H
#define TOKEN_H
#include <stdlib.h>
typedef enum token_type_t {
TOKEN_STRING = 20,
TOKEN_INT = 21,
TOKEN_DECIMAL = 22,
TOKEN_NUMBER = 23,
TOKEN_BOOLEAN = 24,
TOKEN_SYMBOL = 30,
TOKEN_PAREN_OPEN = 31,
TOKEN_PAREN_CLOSE = 32,
TOKEN_BRACE_OPEN = 33,
TOKEN_BRACE_CLOSE = 34,
TOKEN_COMMENT = 2,
TOKEN_MULTILINE_COMMENT = 3,
TOKEN_IS = 60,
TOKEN_DOT = 61,
TOKEN_WHITESPACE = 1,
TOKEN_UNKNOWN = 0,
TOKEN_STAR = 62,
TOKEN_EQUAL = 63,
TOKEN_LT = 64,
TOKEN_LTE = 65,
TOKEN_GT = 66,
TOKEN_GTE = 67,
TOKEN_NOT_EQUAL = 68,
TOKEN_NOT = 69,
TOKEN_MACRO = 4,
TOKEN_WHILE = 50,
TOKEN_FOR = 51,
TOKEN_CLASS = 52,
TOKEN_COMMA = 70
} token_type_t;
typedef struct token_t {
char *value;
size_t length;
token_type_t type;
unsigned int line;
unsigned int col;
unsigned int index;
} token_t;
token_t *token_new() {
token_t *result = (token_t *)calloc(1, sizeof(token_t));
result->value = NULL;
return result;
}
void token_delete(token_t *token) {
if (token->value)
free(token->value);
free(token);
}
void token_dump(token_t *token) {
printf("Type: %d\n", token->type);
printf("Value: <%s>\n", token->value);
printf("Position: %d:%d\n", token->line, token->col);
}
#endif

15
src/utils.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef UTILS_H
#define UTILS_H
#include "parser.h"
size_t get_line_count(char *filepath) {
char *content = read_file_contents(filepath);
lexer_t *lexer = lexer_new();
lexer = lexer_parse(lexer, content);
size_t result = lexer->lines;
lexer_delete(lexer);
free(content);
return result;
}
#endif

View File

@ -0,0 +1,5 @@
class StringA{}
class StringB{}
StringA a = "Test"
StringB b = "Tost"

View File

@ -0,0 +1,5 @@
class String {}
String pony(){}
pony(String arg1, String arg2 = "with_value"){}

View File

@ -0,0 +1 @@
NonExistitingClass A{}

View File

@ -0,0 +1,2 @@
class A {}
class A {}

View File

@ -0,0 +1,8 @@
class Pony {
}
class NotACat(Pony,Pony){
}

5
tests/parser/for.dob Normal file
View File

@ -0,0 +1,5 @@
class Integer {}
for(i = 0 i = 20 i = 30){
// code
Integer j = 55
}

0
tests/parser/globals.dob Normal file
View File

View File

@ -0,0 +1,12 @@
#debug
class Integer {}
Integer i = 1
i = 1
i == 1
i != 1
i > 1
i < 1
i >= 1
i <= 1

18
tests/parser/while.dob Normal file
View File

@ -0,0 +1,18 @@
class String{}
class String2{}
class String3{}
class String4{}
while(){
while(
String a = 2
){
}
}
while(){while(String b = 3){}}
// Nested
while(){while((String c = 4)){String d = 5}}