aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-05-08 22:22:58 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2023-05-08 22:22:58 +0300
commitde86179798fe6d84c8ada1f1414f4def1ba52c3a (patch)
tree52c521b6b57338345d4d5d57e96865113fa03892
parent93c6e4b0b5ef2df6afa1b70483b0bb0fedaacac0 (diff)
downloadek-de86179798fe6d84c8ada1f1414f4def1ba52c3a.tar.gz
ek-de86179798fe6d84c8ada1f1414f4def1ba52c3a.zip
low hanging documentation
-rw-r--r--docs/doxygen.conf2
-rw-r--r--gen/gen_lexer.c198
-rw-r--r--include/ek/actualize.h5
-rw-r--r--include/ek/compiler.h18
-rw-r--r--include/ek/debug.h92
-rw-r--r--include/ek/imports.h16
-rw-r--r--include/ek/path.h21
-rw-r--r--include/ek/string.h75
-rw-r--r--src/compiler.c26
-rw-r--r--src/debug.c39
-rw-r--r--src/lexer.l4
-rw-r--r--src/parser_helper.c1
12 files changed, 382 insertions, 115 deletions
diff --git a/docs/doxygen.conf b/docs/doxygen.conf
index 94a6e76..bf142c9 100644
--- a/docs/doxygen.conf
+++ b/docs/doxygen.conf
@@ -41,7 +41,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
-PROJECT_NAME = ct
+PROJECT_NAME = ek
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
diff --git a/gen/gen_lexer.c b/gen/gen_lexer.c
index 14d7899..1484b6b 100644
--- a/gen/gen_lexer.c
+++ b/gen/gen_lexer.c
@@ -602,11 +602,12 @@ static const flex_int16_t yy_chk[433] =
static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text)
{
+ (void)parser;
+
lloc->first_line = lloc->last_line;
lloc->first_column = lloc->last_column;
for (size_t i = 0; text[i] != 0; ++i) {
- parser->buf_offset++;
if (text[i] == '\n') {
lloc->last_line++;
/* flex uses 1 based indexing */
@@ -618,9 +619,9 @@ static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text
}
#define YY_USER_ACTION update_yylloc(parser, yylloc, yytext);
-#line 622 "gen/gen_lexer.c"
+#line 623 "gen/gen_lexer.c"
-#line 624 "gen/gen_lexer.c"
+#line 625 "gen/gen_lexer.c"
#define INITIAL 0
#define SC_COMMENT 1
@@ -879,9 +880,9 @@ YY_DECL
}
{
-#line 47 "src/lexer.l"
+#line 48 "src/lexer.l"
-#line 885 "gen/gen_lexer.c"
+#line 886 "gen/gen_lexer.c"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@@ -940,23 +941,23 @@ do_action: /* This label is used only to access EOF actions. */
case 1:
YY_RULE_SETUP
-#line 48 "src/lexer.l"
+#line 49 "src/lexer.l"
{/* skip line comments */}
YY_BREAK
case 2:
YY_RULE_SETUP
-#line 50 "src/lexer.l"
+#line 51 "src/lexer.l"
{BEGIN(SC_COMMENT);}
YY_BREAK
case 3:
YY_RULE_SETUP
-#line 52 "src/lexer.l"
+#line 53 "src/lexer.l"
{++parser->comment_nesting;}
YY_BREAK
case 4:
YY_RULE_SETUP
-#line 53 "src/lexer.l"
+#line 54 "src/lexer.l"
{
if (parser->comment_nesting)
--parser->comment_nesting;
@@ -966,135 +967,135 @@ YY_RULE_SETUP
YY_BREAK
case 5:
YY_RULE_SETUP
-#line 60 "src/lexer.l"
+#line 61 "src/lexer.l"
{}
YY_BREAK
case 6:
YY_RULE_SETUP
-#line 61 "src/lexer.l"
+#line 62 "src/lexer.l"
{}
YY_BREAK
case 7:
YY_RULE_SETUP
-#line 62 "src/lexer.l"
+#line 63 "src/lexer.l"
{}
YY_BREAK
case 8:
/* rule 8 can match eol */
YY_RULE_SETUP
-#line 63 "src/lexer.l"
+#line 64 "src/lexer.l"
{}
YY_BREAK
case 9:
YY_RULE_SETUP
-#line 66 "src/lexer.l"
+#line 67 "src/lexer.l"
{return SCOPE;}
YY_BREAK
case 10:
YY_RULE_SETUP
-#line 67 "src/lexer.l"
+#line 68 "src/lexer.l"
{return LPAREN;}
YY_BREAK
case 11:
YY_RULE_SETUP
-#line 68 "src/lexer.l"
+#line 69 "src/lexer.l"
{return RPAREN;}
YY_BREAK
case 12:
YY_RULE_SETUP
-#line 69 "src/lexer.l"
+#line 70 "src/lexer.l"
{return LBRACE;}
YY_BREAK
case 13:
YY_RULE_SETUP
-#line 70 "src/lexer.l"
+#line 71 "src/lexer.l"
{return RBRACE;}
YY_BREAK
case 14:
YY_RULE_SETUP
-#line 71 "src/lexer.l"
+#line 72 "src/lexer.l"
{return LBRACKET;}
YY_BREAK
case 15:
YY_RULE_SETUP
-#line 72 "src/lexer.l"
+#line 73 "src/lexer.l"
{return RBRACKET;}
YY_BREAK
case 16:
YY_RULE_SETUP
-#line 73 "src/lexer.l"
+#line 74 "src/lexer.l"
{return DOT;}
YY_BREAK
case 17:
YY_RULE_SETUP
-#line 74 "src/lexer.l"
+#line 75 "src/lexer.l"
{return COMMA;}
YY_BREAK
case 18:
YY_RULE_SETUP
-#line 75 "src/lexer.l"
+#line 76 "src/lexer.l"
{return SEMICOLON;}
YY_BREAK
case 19:
YY_RULE_SETUP
-#line 76 "src/lexer.l"
+#line 77 "src/lexer.l"
{return COLON;}
YY_BREAK
case 20:
YY_RULE_SETUP
-#line 77 "src/lexer.l"
+#line 78 "src/lexer.l"
{return BANG;}
YY_BREAK
case 21:
YY_RULE_SETUP
-#line 78 "src/lexer.l"
+#line 79 "src/lexer.l"
{return PASTE;}
YY_BREAK
case 22:
YY_RULE_SETUP
-#line 79 "src/lexer.l"
+#line 80 "src/lexer.l"
{return AT;}
YY_BREAK
case 23:
YY_RULE_SETUP
-#line 81 "src/lexer.l"
+#line 82 "src/lexer.l"
{return PLUS;}
YY_BREAK
case 24:
YY_RULE_SETUP
-#line 82 "src/lexer.l"
+#line 83 "src/lexer.l"
{return MINUS;}
YY_BREAK
case 25:
YY_RULE_SETUP
-#line 83 "src/lexer.l"
+#line 84 "src/lexer.l"
{return STAR;}
YY_BREAK
case 26:
YY_RULE_SETUP
-#line 84 "src/lexer.l"
+#line 85 "src/lexer.l"
{return DIV;}
YY_BREAK
case 27:
YY_RULE_SETUP
-#line 85 "src/lexer.l"
+#line 86 "src/lexer.l"
{return REM;}
YY_BREAK
case 28:
YY_RULE_SETUP
-#line 86 "src/lexer.l"
+#line 87 "src/lexer.l"
{return XOR;}
YY_BREAK
case 29:
YY_RULE_SETUP
-#line 87 "src/lexer.l"
+#line 88 "src/lexer.l"
{return POW;}
YY_BREAK
case 30:
/* rule 30 can match eol */
YY_RULE_SETUP
-#line 89 "src/lexer.l"
+#line 90 "src/lexer.l"
{
/* regular character constant, 'a' */
yylval->integer = yytext[1];
@@ -1103,7 +1104,7 @@ YY_RULE_SETUP
YY_BREAK
case 31:
YY_RULE_SETUP
-#line 95 "src/lexer.l"
+#line 96 "src/lexer.l"
{
/* hex character constant, '\xef' */
/* handling is slightly different from C, here it's more or less just
@@ -1114,7 +1115,7 @@ YY_RULE_SETUP
YY_BREAK
case 32:
YY_RULE_SETUP
-#line 103 "src/lexer.l"
+#line 104 "src/lexer.l"
{
/* octal character constant, '\033' */
yylval->integer = strtoll(yytext + 2, NULL, 8);
@@ -1123,7 +1124,7 @@ YY_RULE_SETUP
YY_BREAK
case 33:
YY_RULE_SETUP
-#line 109 "src/lexer.l"
+#line 110 "src/lexer.l"
{
/* binary character constant, '\b101' */
yylval->integer = strtoll(yytext + 3, NULL, 2);
@@ -1132,7 +1133,7 @@ YY_RULE_SETUP
YY_BREAK
case 34:
YY_RULE_SETUP
-#line 115 "src/lexer.l"
+#line 116 "src/lexer.l"
{
/* escaped character constant */
yylval->integer = match_escape(yytext[2]);
@@ -1141,273 +1142,273 @@ YY_RULE_SETUP
YY_BREAK
case 35:
YY_RULE_SETUP
-#line 121 "src/lexer.l"
+#line 122 "src/lexer.l"
{return SQUOTE;}
YY_BREAK
case 36:
YY_RULE_SETUP
-#line 123 "src/lexer.l"
+#line 124 "src/lexer.l"
{return AND;}
YY_BREAK
case 37:
YY_RULE_SETUP
-#line 124 "src/lexer.l"
+#line 125 "src/lexer.l"
{return LAND;}
YY_BREAK
case 38:
YY_RULE_SETUP
-#line 125 "src/lexer.l"
+#line 126 "src/lexer.l"
{return OR;}
YY_BREAK
case 39:
YY_RULE_SETUP
-#line 126 "src/lexer.l"
+#line 127 "src/lexer.l"
{return LOR;}
YY_BREAK
case 40:
YY_RULE_SETUP
-#line 128 "src/lexer.l"
+#line 129 "src/lexer.l"
{return TILDE;}
YY_BREAK
case 41:
YY_RULE_SETUP
-#line 129 "src/lexer.l"
+#line 130 "src/lexer.l"
{return TO;}
YY_BREAK
case 42:
YY_RULE_SETUP
-#line 130 "src/lexer.l"
+#line 131 "src/lexer.l"
{return LT;}
YY_BREAK
case 43:
YY_RULE_SETUP
-#line 131 "src/lexer.l"
+#line 132 "src/lexer.l"
{return GT;}
YY_BREAK
case 44:
YY_RULE_SETUP
-#line 132 "src/lexer.l"
+#line 133 "src/lexer.l"
{return LE;}
YY_BREAK
case 45:
YY_RULE_SETUP
-#line 133 "src/lexer.l"
+#line 134 "src/lexer.l"
{return GE;}
YY_BREAK
case 46:
YY_RULE_SETUP
-#line 134 "src/lexer.l"
+#line 135 "src/lexer.l"
{return NE;}
YY_BREAK
case 47:
YY_RULE_SETUP
-#line 135 "src/lexer.l"
+#line 136 "src/lexer.l"
{return EQ;}
YY_BREAK
case 48:
YY_RULE_SETUP
-#line 137 "src/lexer.l"
+#line 138 "src/lexer.l"
{return FATARROW;}
YY_BREAK
case 49:
YY_RULE_SETUP
-#line 139 "src/lexer.l"
+#line 140 "src/lexer.l"
{return LSHIFT;}
YY_BREAK
case 50:
YY_RULE_SETUP
-#line 140 "src/lexer.l"
+#line 141 "src/lexer.l"
{return RSHIFT;}
YY_BREAK
case 51:
YY_RULE_SETUP
-#line 142 "src/lexer.l"
+#line 143 "src/lexer.l"
{return PLUSSELF;}
YY_BREAK
case 52:
YY_RULE_SETUP
-#line 143 "src/lexer.l"
+#line 144 "src/lexer.l"
{return MINUSSELF;}
YY_BREAK
case 53:
YY_RULE_SETUP
-#line 144 "src/lexer.l"
+#line 145 "src/lexer.l"
{return DIVSELF;}
YY_BREAK
case 54:
YY_RULE_SETUP
-#line 145 "src/lexer.l"
+#line 146 "src/lexer.l"
{return REMSELF;}
YY_BREAK
case 55:
YY_RULE_SETUP
-#line 146 "src/lexer.l"
+#line 147 "src/lexer.l"
{return XORSELF;}
YY_BREAK
case 56:
YY_RULE_SETUP
-#line 147 "src/lexer.l"
+#line 148 "src/lexer.l"
{return POWSELF;}
YY_BREAK
case 57:
YY_RULE_SETUP
-#line 148 "src/lexer.l"
+#line 149 "src/lexer.l"
{return ORSELF;}
YY_BREAK
case 58:
YY_RULE_SETUP
-#line 149 "src/lexer.l"
+#line 150 "src/lexer.l"
{return ORSELF;}
YY_BREAK
case 59:
YY_RULE_SETUP
-#line 150 "src/lexer.l"
+#line 151 "src/lexer.l"
{return LSHIFTSELF;}
YY_BREAK
case 60:
YY_RULE_SETUP
-#line 151 "src/lexer.l"
+#line 152 "src/lexer.l"
{return RSHIFTSELF;}
YY_BREAK
case 61:
YY_RULE_SETUP
-#line 152 "src/lexer.l"
+#line 153 "src/lexer.l"
{return ELLIPSIS;}
YY_BREAK
case 62:
YY_RULE_SETUP
-#line 154 "src/lexer.l"
+#line 155 "src/lexer.l"
{return AS;}
YY_BREAK
case 63:
YY_RULE_SETUP
-#line 155 "src/lexer.l"
+#line 156 "src/lexer.l"
{return PUB;}
YY_BREAK
case 64:
YY_RULE_SETUP
-#line 156 "src/lexer.l"
+#line 157 "src/lexer.l"
{return DEFER;}
YY_BREAK
case 65:
YY_RULE_SETUP
-#line 157 "src/lexer.l"
+#line 158 "src/lexer.l"
{return UNION;}
YY_BREAK
case 66:
YY_RULE_SETUP
-#line 158 "src/lexer.l"
+#line 159 "src/lexer.l"
{return STRUCT;}
YY_BREAK
case 67:
YY_RULE_SETUP
-#line 159 "src/lexer.l"
+#line 160 "src/lexer.l"
{return TYPEDEF;}
YY_BREAK
case 68:
YY_RULE_SETUP
-#line 160 "src/lexer.l"
+#line 161 "src/lexer.l"
{return IMPORT;}
YY_BREAK
case 69:
YY_RULE_SETUP
-#line 161 "src/lexer.l"
+#line 162 "src/lexer.l"
{return TYPEOF;}
YY_BREAK
case 70:
YY_RULE_SETUP
-#line 162 "src/lexer.l"
+#line 163 "src/lexer.l"
{return SIZEOF;}
YY_BREAK
case 71:
YY_RULE_SETUP
-#line 163 "src/lexer.l"
+#line 164 "src/lexer.l"
{return EMBED;}
YY_BREAK
case 72:
YY_RULE_SETUP
-#line 164 "src/lexer.l"
+#line 165 "src/lexer.l"
{return IF;}
YY_BREAK
case 73:
YY_RULE_SETUP
-#line 165 "src/lexer.l"
+#line 166 "src/lexer.l"
{return GOTO;}
YY_BREAK
case 74:
YY_RULE_SETUP
-#line 166 "src/lexer.l"
+#line 167 "src/lexer.l"
{return ELSE;}
YY_BREAK
case 75:
YY_RULE_SETUP
-#line 167 "src/lexer.l"
+#line 168 "src/lexer.l"
{return SWITCH;}
YY_BREAK
case 76:
YY_RULE_SETUP
-#line 168 "src/lexer.l"
+#line 169 "src/lexer.l"
{return CASE;}
YY_BREAK
case 77:
YY_RULE_SETUP
-#line 169 "src/lexer.l"
+#line 170 "src/lexer.l"
{return FOR;}
YY_BREAK
case 78:
YY_RULE_SETUP
-#line 170 "src/lexer.l"
+#line 171 "src/lexer.l"
{return WHILE;}
YY_BREAK
case 79:
YY_RULE_SETUP
-#line 171 "src/lexer.l"
+#line 172 "src/lexer.l"
{return DO;}
YY_BREAK
case 80:
YY_RULE_SETUP
-#line 172 "src/lexer.l"
+#line 173 "src/lexer.l"
{return MUT;}
YY_BREAK
case 81:
YY_RULE_SETUP
-#line 173 "src/lexer.l"
+#line 174 "src/lexer.l"
{return CONST;}
YY_BREAK
case 82:
YY_RULE_SETUP
-#line 174 "src/lexer.l"
+#line 175 "src/lexer.l"
{return RETURN;}
YY_BREAK
case 83:
YY_RULE_SETUP
-#line 175 "src/lexer.l"
+#line 176 "src/lexer.l"
{return EXTERN;}
YY_BREAK
case 84:
YY_RULE_SETUP
-#line 176 "src/lexer.l"
+#line 177 "src/lexer.l"
{return ENUM;}
YY_BREAK
case 85:
YY_RULE_SETUP
-#line 177 "src/lexer.l"
+#line 178 "src/lexer.l"
{return DEFINE;}
YY_BREAK
case 86:
YY_RULE_SETUP
-#line 178 "src/lexer.l"
+#line 179 "src/lexer.l"
{return BREAK;}
YY_BREAK
case 87:
YY_RULE_SETUP
-#line 179 "src/lexer.l"
+#line 180 "src/lexer.l"
{return CONTINUE;}
YY_BREAK
case 88:
/* rule 88 can match eol */
YY_RULE_SETUP
-#line 181 "src/lexer.l"
+#line 182 "src/lexer.l"
{
/* seems risky, I know, but letting the parser choose when to allocate a
* new string seems to help with syntax error cleanup */
@@ -1417,7 +1418,7 @@ YY_RULE_SETUP
YY_BREAK
case 89:
YY_RULE_SETUP
-#line 188 "src/lexer.l"
+#line 189 "src/lexer.l"
{
yylval->integer = strtoll(yytext, 0, 0);
return INT;
@@ -1425,7 +1426,7 @@ YY_RULE_SETUP
YY_BREAK
case 90:
YY_RULE_SETUP
-#line 193 "src/lexer.l"
+#line 194 "src/lexer.l"
{
yylval->dbl = strtod(yytext, 0);
return FLOAT;
@@ -1433,7 +1434,7 @@ YY_RULE_SETUP
YY_BREAK
case 91:
YY_RULE_SETUP
-#line 198 "src/lexer.l"
+#line 199 "src/lexer.l"
{
yylval->str = yytext;
return ID;
@@ -1442,19 +1443,18 @@ YY_RULE_SETUP
case 92:
/* rule 92 can match eol */
YY_RULE_SETUP
-#line 204 "src/lexer.l"
+#line 205 "src/lexer.l"
{/* skip whitespace */}
YY_BREAK
case 93:
YY_RULE_SETUP
-#line 206 "src/lexer.l"
+#line 207 "src/lexer.l"
{
struct src_issue issue;
issue.level = SRC_ERROR;
issue.loc = to_src_loc(yylloc);
issue.fctx.fbuf = parser->buf;
issue.fctx.fname = parser->fname;
- issue.offset = parser->buf_offset;
src_issue(issue, "Unexpected token: %s", yytext);
parser->failed = true;
}
diff --git a/include/ek/actualize.h b/include/ek/actualize.h
index 18755b1..9cee764 100644
--- a/include/ek/actualize.h
+++ b/include/ek/actualize.h
@@ -7,9 +7,8 @@
/**
* @file actualize.h
*
- * Actualization stuff, that is stuff needed for turning raw AST
- * into processed AST that can be passed to a backend to generate
- * code.
+ * Actualization stuff needed for turning raw AST
+ * into processed AST that can be passed to a backend to generate code.
*/
#include <assert.h>
diff --git a/include/ek/compiler.h b/include/ek/compiler.h
index 8e3d221..32fc218 100644
--- a/include/ek/compiler.h
+++ b/include/ek/compiler.h
@@ -12,7 +12,25 @@
#include <ek/scope.h>
+/**
+ * Compile a root file.
+ * A root file is a file given on the command line, and is assumed to
+ * create a file tree that eventually results in a binary.
+ *
+ * @param file Root file to compile.
+ * @return \c 0 if compilation was succesful, otherwise some non-zero value.
+ */
int compile(const char *file);
+
+/**
+ * Process a file, i.e. lex, parse and generate raw AST.
+ *
+ * @param parent Parent scope of file from which \p file is imported.
+ * \c NULL if root file.
+ * @param public \c 1 if \p file should be publicly imported, \c 0 otherwise.
+ * @param file File to process.
+ * @return \c 0 if compilation was succesful, otherwise some non-zero value.
+ */
int process_file(struct scope **parent, int public, const char *file);
#endif /* EK_COMPILER_H */
diff --git a/include/ek/debug.h b/include/ek/debug.h
index 7dca003..d222cf4 100644
--- a/include/ek/debug.h
+++ b/include/ek/debug.h
@@ -15,49 +15,139 @@
#include <ek/ast.h>
#if DEBUG
+/**
+ * Print debugging message. Only active if \c DEBUG is defined,
+ *
+ * @param x Format string. Follows standard printf() formatting.
+ */
#define debug(x, ...) \
do {fprintf(stderr, "debug: " x "\n",##__VA_ARGS__);} while(0)
#else
#define debug(x, ...)
#endif
+/**
+ * Print error message.
+ *
+ * @param x Format string. Follows standard printf() formatting.
+ */
#define error(x, ...) \
do {fprintf(stderr, "error: " x "\n",##__VA_ARGS__);} while(0)
+/**
+ * Print warning message.
+ *
+ * @param x Format string. Follows standard printf() formatting.
+ */
#define warn(x, ...) \
do {fprintf(stderr, "warn: " x "\n",##__VA_ARGS__);} while(0)
+/**
+ * Print info message.
+ *
+ * @param x Format string. Follows standard printf() formatting.
+ */
#define info(x, ...) \
do {fprintf(stderr, "info: " x "\n",##__VA_ARGS__);} while(0)
+/** Keeps track of file name and file buffer. */
struct file_ctx {
+ /** File name. */
const char *fname;
+ /** File buffer. */
const char *fbuf;
};
+/**
+ * Generate string representation of type.
+ *
+ * @param type Type to generate string representation of.
+ * @return \p type as string.
+ */
char *type_str(struct ast_node *type);
+
+/**
+ * Generate string representation of call.
+ *
+ * @param call Call to generate string representation of.
+ * @return \p call as string.
+ */
char *call_str(struct ast_node *call);
+
+/**
+ * Print info that relates to a specific AST node.
+ * Recommended for situations where it may be useful to clarify some
+ * previous error or warning.
+ *
+ * @param ctx File context \p node was generated from.
+ * @param node AST node to print message with.
+ * @param fmt Format string. Follows standard printf() formatting.
+ */
void semantic_info(struct file_ctx ctx, struct ast_node *node, const char *fmt,
...);
+
+/**
+ * Print warning that relates to a specific AST node.
+ * Recommended for situations where the user wrote some shady code
+ * and it might be unclear what was meant.
+ *
+ * The language itself tries to avoid such situations, and as such warnings
+ * should probably be avoided in favor of errors. Still, I can imagine that
+ * there are situations where warnings can be useful, so it's provided.
+ *
+ * @param ctx File context \p node was generated from.
+ * @param node AST node to print message with.
+ * @param fmt Format string. Follows standard printf() formatting.
+ */
void semantic_warn(struct file_ctx ctx, struct ast_node *node, const char *fmt,
...);
+
+/**
+ * Print warning that relates to a specific AST node.
+ * Recommended for situations where the user messed up.
+ *
+ * @param ctx File context \p node was generated from.
+ * @param node AST node to print message with.
+ * @param fmt Format string. Follows standard printf() formatting.
+ */
void semantic_error(struct file_ctx ctx, struct ast_node *node, const char *fmt,
...);
+
+/**
+ * Print internal error.
+ * Recommended for situations where the developer (probably me) messed up.
+ *
+ * @param fmt Format string. Follows standard printf() formatting.
+ */
void internal_error(const char *fmt, ...);
+/** Issue categorization. */
enum issue_level {
+ /** Information. */
SRC_INFO,
+ /** Warning. */
SRC_WARN,
+ /** Error. */
SRC_ERROR
};
+/** Context for issue in user code. */
struct src_issue {
+ /** How bad the issue is. */
enum issue_level level;
+ /** Where the issue happened relative to file buffer. */
struct src_loc loc;
+ /** File context issue happened in. */
struct file_ctx fctx;
- size_t offset;
};
+/**
+ * Print a source issue.
+ *
+ * @param issue Context for issue.
+ * @param err_msg Format string. Follows standard printf() formatting.
+ */
void src_issue(struct src_issue issue, const char *err_msg, ...);
+
#endif /* EK_DEBUG_H */
diff --git a/include/ek/imports.h b/include/ek/imports.h
index 801eb06..43603c4 100644
--- a/include/ek/imports.h
+++ b/include/ek/imports.h
@@ -9,13 +9,25 @@
*
* File import handling.
* Currently mostly unimplemented, but intended to keep track
- * of which files have been imported.
+ * of where to find files for import.
*/
#include <stdbool.h>
+/**
+ * Add import path to search for files in.
+ *
+ * @param dir Directory to search files in. Either absolute or relative.
+ */
void add_import_path(const char *dir);
+
+/**
+ * Search for \p file in import path.
+ * @todo implement.
+ *
+ * @param file File name to search for.
+ * @return Full path to \p file if found, \c NULL otherwise.
+ */
const char *find_import(const char *file);
-bool already_imported(const char *file);
#endif /* EK_IMPORTS_H */
diff --git a/include/ek/path.h b/include/ek/path.h
index 2ddfb4c..2e15932 100644
--- a/include/ek/path.h
+++ b/include/ek/path.h
@@ -10,8 +10,29 @@
* Path handling helpers.
*/
+/**
+ * Get basename of file path.
+ * E.g. src/some/file.c -> file.c
+ *
+ * @param file File path to get basename from.
+ * @return Basename of \p file.
+ */
char *ek_basename(const char *file);
+
+/**
+ * Get directory name of path.
+ * E.g. src/some/file.c -> src/some
+ *
+ * @param file File path to get dirname from.
+ * @return Dirname of \p file.
+ */
char *ek_dirname(const char *file);
+
+/**
+ * Get current working directory.
+ *
+ * @return Current working directory.
+ */
char *ek_cwdname();
#endif /* EK_PATH */
diff --git a/include/ek/string.h b/include/ek/string.h
index 5c561a7..bbe8779 100644
--- a/include/ek/string.h
+++ b/include/ek/string.h
@@ -9,28 +9,103 @@
*
* String handling helper stuff.
* At the moment mostly unused.
+ * Doesn't implement short string optimizations or anything like that for now.
*/
#include <stddef.h>
#include <string.h>
#include <stdbool.h>
+/** Simple representation of a string. */
struct string {
+ /** Lenght of string. */
size_t len;
+ /** String buffer. */
char *buf;
};
+/**
+ * Create new string from null terminated character array.
+ * Allocates a string object on the heap and copies \p s into it.
+ *
+ * @param s Null terminated character array.
+ * @return \p s as a string.
+ */
struct string *new_string(const char *s);
+
+/**
+ * Destroy previously created string.
+ * Frees the string and anything associated with it.
+ *
+ * @param s String to destroy.
+ */
void destroy_string(struct string *s);
+/**
+ * Append a character to a string.
+ *
+ * @param s String to append \c to.
+ * @param c Character to append to \p s.
+ * @return \c 0 if appending succeeded, non-zero otherwise.
+ */
int str_append(struct string *s, char c);
+
+/**
+ * Concatenate a string and a null terminated character array.
+ * Essentially adds \p c to the end of \p s.
+ *
+ * @param s String to concatenate \p c with.
+ * @param c Null terminated character array to concatenate with \p s.
+ * @return \c 0 if concatenation succeeded, non-zero otherwise.
+ */
int str_concat(struct string *s, const char *c);
+
+/**
+ * Add \p c to the end of \p s.
+ *
+ * @param s String to add \p c to.
+ * @param c String to att to \p s.
+ * @return \c 0 if addition succeedes, non-zero otherwise.
+ */
int str_add(struct string *s, struct string *c);
+/**
+ * Get character at index \p i in \p s.
+ *
+ * @todo implement, range checking?
+ *
+ * @param s String to index into.
+ * @param i Index of character to get.
+ * @return Character at \p i in \p s.
+ */
char str_index(struct string *s, size_t i);
+
+/**
+ * Get character at index \p i from the end of \p s.
+ *
+ * @todo implement, range checking?
+ *
+ * @param s String to index into?
+ * @param i Index of character from the end to get.
+ * @return Character at \p i from the end of \p s.
+ */
char str_rindex(struct string *s, size_t i);
+/**
+ * Compare string with null-terminated character array.
+ * Essentially a wrapper around strncmp().
+ *
+ * @param s String to compare against \p c.
+ * @param c Null-terminated array to compare against \p s.
+ * @return \c true if identical, \c false otherwise.
+ */
bool str_compare(struct string *s, const char *c);
+
+/**
+ * Clear content of string.
+ *
+ * @param s String to clear content of.
+ */
void str_clear(struct string *s);
#endif /* EK_STRING_H */
diff --git a/src/compiler.c b/src/compiler.c
index 68414c7..607618e 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -24,10 +24,20 @@
#include <ek/path.h>
#include <ek/res.h>
+/**
+ * Read whole file into a buffer and return pointer to buffer.
+ * Possibly kind of silly to have both \p file and \p f.
+ * Apparently there's no standardized way to get the file name of a
+ * file pointer.
+ *
+ * @param file Name of file to read.
+ * @param f File pointer.
+ * @return Pointer to buffer with file contents.
+ */
static char *read_file(const char *file, FILE *f)
{
fseek(f, 0, SEEK_END);
- /* TODO: check how well standardized this actually is */
+ /** @todo check how well standardized this actually is */
long s = ftell(f);
if (s == LONG_MAX) {
error("%s might be a directory", file);
@@ -46,6 +56,16 @@ static char *read_file(const char *file, FILE *f)
return buf;
}
+/**
+ * Helper for process_file(), actually processes the file
+ * after process_file() has done path lookups and working directory
+ * changes and whatnot.
+ *
+ * @param parent Parent file context. \c NULL if root file.
+ * @param public \c 1 if file is being imported publicly, \c 0 otherwise.
+ * @param file File name to process.
+ * @return \c 0 if processing was succesful, non-zero value otherwise.
+ */
static int process(struct scope **parent, int public, const char *file)
{
FILE *f = fopen(file, "rb");
@@ -99,7 +119,7 @@ static int process(struct scope **parent, int public, const char *file)
int process_file(struct scope **scope, int public, const char *file)
{
int res = -1;
- /* TODO: report failure allocating stuff maybe? */
+ /** todo report failure allocating stuff maybe? */
struct res *r = res_create();
if (!r)
return -1;
@@ -153,7 +173,7 @@ int compile(const char *file) {
}
ret = actualize_main(root);
- /* TODO: backend */
+ /** @todo backend */
destroy_scope(root);
return ret;
}
diff --git a/src/debug.c b/src/debug.c
index 1be19af..017f07f 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -16,6 +16,12 @@
#include <ek/debug.h>
+/**
+ * Get string representation of issue_level.
+ *
+ * @param level issue_level to get string representation for.
+ * @return \p level as a string.
+ */
const char *issue_level_str(enum issue_level level)
{
switch (level) {
@@ -27,9 +33,19 @@ const char *issue_level_str(enum issue_level level)
return "unknown";
}
+/**
+ * Find position in file buffer where line number \p no
+ * starts. Lines are assumed to be one-indexed, with
+ * \p no = \c 0 and \p no = \c 1 both considered the first line.
+ *
+ * @param buf Buffer to look in.
+ * @param no Line number whose start to look for.
+ * @return Pointer to location in buffer where line number \p no
+ * starts.
+ */
static const char *find_lineno(const char *buf, size_t no)
{
- if (no == 1)
+ if (no == 0 || no == 1)
return buf;
char c;
@@ -46,6 +62,13 @@ static const char *find_lineno(const char *buf, size_t no)
return buf;
}
+/**
+ * Helper for printing out an issue.
+ *
+ * @param issue Issue context.
+ * @param fmt Format string. Follows standard printf() formatting.
+ * @param args Arguments for \p fmt.
+ */
static void _issue(struct src_issue issue, const char *fmt, va_list args)
{
/* get start and end of current line in buffer */
@@ -97,8 +120,6 @@ void src_issue(struct src_issue issue, const char *err_msg, ...)
va_end(args);
}
-/* TODO: should really implement these better, the bad error messages are
- * starting to play a role in debugging */
void semantic_error(struct file_ctx fctx, struct ast_node *node,
const char *fmt, ...)
{
@@ -148,6 +169,12 @@ void internal_error(const char *fmt, ...)
va_end(args);
}
+/**
+ * Workhorse for type_str().
+ *
+ * @param fp File pointer to write string representation to.
+ * @param type Type to generate string representation for.
+ */
static void _type_str(FILE *fp, struct ast_node *type)
{
if (!type)
@@ -269,6 +296,12 @@ char *type_str(struct ast_node *node)
return buf;
}
+/**
+ * Workhorse for call_str().
+ *
+ * @param f File pointer to write string representation to.
+ * @param call Call to generate string representation for.
+ */
static void _call_str(FILE *f, struct ast_node *call)
{
struct ast_node *id = call->_call.id;
diff --git a/src/lexer.l b/src/lexer.l
index c855287..c30e802 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -9,11 +9,12 @@
static void update_yylloc(struct parser *parser, YYLTYPE *lloc, const char *text)
{
+ (void)parser;
+
lloc->first_line = lloc->last_line;
lloc->first_column = lloc->last_column;
for (size_t i = 0; text[i] != 0; ++i) {
- parser->buf_offset++;
if (text[i] == '\n') {
lloc->last_line++;
/* flex uses 1 based indexing */
@@ -209,7 +210,6 @@ STRING \"(\\.|[^"\\])*\"
issue.loc = to_src_loc(yylloc);
issue.fctx.fbuf = parser->buf;
issue.fctx.fname = parser->fname;
- issue.offset = parser->buf_offset;
src_issue(issue, "Unexpected token: %s", yytext);
parser->failed = true;
}
diff --git a/src/parser_helper.c b/src/parser_helper.c
index 15dd6e8..5a90df8 100644
--- a/src/parser_helper.c
+++ b/src/parser_helper.c
@@ -87,7 +87,6 @@ void yyerror(YYLTYPE *yylloc, void *lexer, struct parser *parser,
issue.loc = to_src_loc(yylloc);
issue.fctx.fbuf = parser->buf;
issue.fctx.fname = parser->fname;
- issue.offset = parser->buf_offset;
src_issue(issue, msg);
}