Browse Source

Sol Part 46: POOOOSIX POOOWEEEERRRRRR!!!

Fixes #20
master
Graham Northup 6 years ago
parent
commit
f08f6a2c62
  1. 64
      ast.h
  2. 120
      lex.yy.c
  3. 290
      sol.h
  4. 53
      state.c

64
ast.h

@ -5,6 +5,10 @@
#include <stdio.h>
/** Locator structure.
*
* Contains the location of a symbol; available on all `stmt_node`s and `expr_node`s as `loc`.
*/
typedef struct {
size_t line;
size_t col;
@ -16,38 +20,70 @@ typedef struct tag_expr_node expr_node;
struct tag_stmt_node;
typedef struct tag_stmt_node stmt_node;
/** Literal type
*
* Defines the types of literals that may appear in a source program.
*/
typedef enum {LIT_INT, LIT_FLOAT, LIT_STRING, LIT_NONE} lit_t;
/** Literal node
*
* Represents a literal in a source program.
*/
typedef struct {
lit_t type;
lit_t type; ///< The type of literal.
union {
long ival;
double fval;
char *str;
long ival; ///< Integer value for `LIT_INT`.
double fval; ///< Floating-point value for `LIT_FLOAT`.
char *str; ///< String value for `LIT_STRING`.
};
} lit_node;
/** Binary operation type
*
* Defines the types of binary operators that may occur in a source program.
*/
typedef enum {OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW, OP_BAND, OP_BOR, OP_BXOR, OP_LAND, OP_LOR, OP_EQUAL, OP_NEQUAL, OP_LESS, OP_GREATER, OP_LESSEQ, OP_GREATEREQ, OP_LSHIFT, OP_RSHIFT, OP_TBANG} binop_t;
/** Binary operation node
*
* Represents a binary operator in a source program.
*/
typedef struct {
binop_t type;
expr_node *left;
expr_node *right;
binop_t type; ///< The type of binary operation
expr_node *left; ///< The left hand side.
expr_node *right; ///< The right hand side.
} binop_node;
/** Unary operation type
*
* Defines the types of unary operators that may occur in a source program.
*/
typedef enum {OP_NEG, OP_BNOT, OP_LNOT, OP_LEN} unop_t;
/** Unary opreation node
*
* Represents a unary operator in a source program.
*/
typedef struct {
unop_t type;
expr_node *expr;
unop_t type; ///< The type of unary operation.
expr_node *expr; ///< The value to which it is applied.
} unop_node;
/** Index node
*
* Represents an index operation in a source program.
*/
typedef struct {
expr_node *expr;
expr_node *index;
expr_node *expr; ///< Expression to index.
expr_node *index; ///< Expression to index by.
} index_node;
/** Setindex node
*
* Represents a setindex operation in a source program.
*/
typedef struct {
expr_node *expr;
expr_node *index;
expr_node *value;
expr_node *expr; ///< Expression to set the index of.
expr_node *index; ///< Expression to index by.
expr_node *value; ///< Value to set said index to.
} setindex_node;
typedef struct {

120
lex.yy.c

@ -7,8 +7,8 @@
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#define YY_FLEX_SUBMINOR_VERSION 39
#define YY_FLEX_MINOR_VERSION 6
#define YY_FLEX_SUBMINOR_VERSION 0
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
@ -352,11 +352,17 @@ extern int yylineno;
int yylineno = 1;
extern char *yytext;
#ifdef yytext_ptr
#undef yytext_ptr
#endif
#define yytext_ptr yytext
static yy_state_type yy_get_previous_state (void );
static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
static int yy_get_next_buffer (void );
#if defined(__GNUC__) && __GNUC__ >= 3
__attribute__((__noreturn__))
#endif
static void yy_fatal_error (yyconst char msg[] );
/* Done after the current pattern has been matched and before the
@ -398,7 +404,7 @@ static yyconst flex_int16_t yy_accept[148] =
8, 69, 13, 14, 69, 16, 0
} ;
static yyconst flex_int32_t yy_ec[256] =
static yyconst YY_CHAR yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -430,7 +436,7 @@ static yyconst flex_int32_t yy_ec[256] =
1, 1, 1, 1, 1
} ;
static yyconst flex_int32_t yy_meta[53] =
static yyconst YY_CHAR yy_meta[53] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2, 1, 1,
@ -440,7 +446,7 @@ static yyconst flex_int32_t yy_meta[53] =
1, 1
} ;
static yyconst flex_int16_t yy_base[152] =
static yyconst flex_uint16_t yy_base[152] =
{ 0,
0, 0, 161, 162, 51, 51, 155, 162, 162, 48,
150, 162, 162, 45, 136, 162, 43, 162, 135, 43,
@ -482,7 +488,7 @@ static yyconst flex_int16_t yy_def[152] =
147
} ;
static yyconst flex_int16_t yy_nxt[215] =
static yyconst flex_uint16_t yy_nxt[215] =
{ 0,
4, 5, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
@ -627,7 +633,7 @@ static void update_loc(YYLTYPE *yylloc, char *yytext){
<STRING>. { str_putc(*yytext); }
*/
#line 631 "lex.yy.c"
#line 637 "lex.yy.c"
#define INITIAL 0
@ -660,11 +666,11 @@ void yyset_extra (YY_EXTRA_TYPE user_defined );
FILE *yyget_in (void );
void yyset_in (FILE * in_str );
void yyset_in (FILE * _in_str );
FILE *yyget_out (void );
void yyset_out (FILE * out_str );
void yyset_out (FILE * _out_str );
yy_size_t yyget_leng (void );
@ -672,7 +678,7 @@ char *yyget_text (void );
int yyget_lineno (void );
void yyset_lineno (int line_number );
void yyset_lineno (int _line_number );
YYSTYPE * yyget_lval (void );
@ -694,8 +700,12 @@ extern int yywrap (void );
#endif
#endif
#ifndef YY_NO_UNPUT
static void yyunput (int c,char *buf_ptr );
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy (char *,yyconst char *,int );
#endif
@ -810,7 +820,7 @@ extern int yylex \
/* Code executed at the end of each rule. */
#ifndef YY_BREAK
#define YY_BREAK break;
#define YY_BREAK /*LINTED*/break;
#endif
#define YY_RULE_SETUP \
@ -820,9 +830,9 @@ extern int yylex \
*/
YY_DECL
{
register yy_state_type yy_current_state;
register char *yy_cp, *yy_bp;
register int yy_act;
yy_state_type yy_current_state;
char *yy_cp, *yy_bp;
int yy_act;
YYSTYPE * yylval;
@ -862,9 +872,9 @@ YY_DECL
#line 85 "tokenizer.lex"
#line 866 "lex.yy.c"
#line 876 "lex.yy.c"
while ( 1 ) /* loops until end-of-file is reached */
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
yy_cp = (yy_c_buf_p);
@ -880,7 +890,7 @@ YY_DECL
yy_match:
do
{
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
@ -1283,7 +1293,7 @@ YY_RULE_SETUP
#line 229 "tokenizer.lex"
ECHO;
YY_BREAK
#line 1287 "lex.yy.c"
#line 1297 "lex.yy.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
@ -1426,9 +1436,9 @@ case YY_STATE_EOF(INITIAL):
*/
static int yy_get_next_buffer (void)
{
register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
register char *source = (yytext_ptr);
register int number_to_move, i;
char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
char *source = (yytext_ptr);
yy_size_t number_to_move, i;
int ret_val;
if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
@ -1457,7 +1467,7 @@ static int yy_get_next_buffer (void)
/* Try to read more data. */
/* First move last chars to start of buffer. */
number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1;
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
@ -1560,14 +1570,14 @@ static int yy_get_next_buffer (void)
static yy_state_type yy_get_previous_state (void)
{
register yy_state_type yy_current_state;
register char *yy_cp;
yy_state_type yy_current_state;
char *yy_cp;
yy_current_state = (yy_start);
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
{
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
@ -1592,10 +1602,10 @@ static int yy_get_next_buffer (void)
*/
static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
{
register int yy_is_jam;
register char *yy_cp = (yy_c_buf_p);
int yy_is_jam;
char *yy_cp = (yy_c_buf_p);
register YY_CHAR yy_c = 1;
YY_CHAR yy_c = 1;
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
@ -1613,9 +1623,11 @@ static int yy_get_next_buffer (void)
return yy_is_jam ? 0 : yy_current_state;
}
static void yyunput (int c, register char * yy_bp )
#ifndef YY_NO_UNPUT
static void yyunput (int c, char * yy_bp )
{
register char *yy_cp;
char *yy_cp;
yy_cp = (yy_c_buf_p);
@ -1625,10 +1637,10 @@ static int yy_get_next_buffer (void)
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
{ /* need to shift things up to make room */
/* +2 for EOB chars. */
register yy_size_t number_to_move = (yy_n_chars) + 2;
register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
yy_size_t number_to_move = (yy_n_chars) + 2;
char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
register char *source =
char *source =
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
@ -1650,6 +1662,8 @@ static int yy_get_next_buffer (void)
(yy_c_buf_p) = yy_cp;
}
#endif
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput (void)
@ -1799,7 +1813,7 @@ static void yy_load_buffer_state (void)
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
b->yy_buf_size = size;
b->yy_buf_size = (yy_size_t)size;
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
@ -1954,7 +1968,7 @@ static void yyensure_buffer_stack (void)
* scanner will even need a stack. We use 2 instead of 1 to avoid an
* immediate realloc on the next call.
*/
num_to_alloc = 1;
num_to_alloc = 1; // After all that talk, this was set to 1 anyways...
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
);
@ -1971,7 +1985,7 @@ static void yyensure_buffer_stack (void)
if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
/* Increase the buffer to prepare for a possible push. */
int grow_size = 8 /* arbitrary grow size */;
yy_size_t grow_size = 8 /* arbitrary grow size */;
num_to_alloc = (yy_buffer_stack_max) + grow_size;
(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
@ -2079,7 +2093,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len
static void yy_fatal_error (yyconst char* msg )
{
(void) fprintf( stderr, "%s\n", msg );
(void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
}
@ -2145,29 +2159,29 @@ char *yyget_text (void)
}
/** Set the current line number.
* @param line_number
* @param _line_number line number
*
*/
void yyset_lineno (int line_number )
void yyset_lineno (int _line_number )
{
yylineno = line_number;
yylineno = _line_number;
}
/** Set the input stream. This does not discard the current
* input buffer.
* @param in_str A readable stream.
* @param _in_str A readable stream.
*
* @see yy_switch_to_buffer
*/
void yyset_in (FILE * in_str )
void yyset_in (FILE * _in_str )
{
yyin = in_str ;
yyin = _in_str ;
}
void yyset_out (FILE * out_str )
void yyset_out (FILE * _out_str )
{
yyout = out_str ;
yyout = _out_str ;
}
int yyget_debug (void)
@ -2175,9 +2189,9 @@ int yyget_debug (void)
return yy_flex_debug;
}
void yyset_debug (int bdebug )
void yyset_debug (int _bdebug )
{
yy_flex_debug = bdebug ;
yy_flex_debug = _bdebug ;
}
static int yy_init_globals (void)
@ -2237,7 +2251,8 @@ int yylex_destroy (void)
#ifndef yytext_ptr
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
{
register int i;
int i;
for ( i = 0; i < n; ++i )
s1[i] = s2[i];
}
@ -2246,7 +2261,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * s )
{
register int n;
int n;
for ( n = 0; s[n]; ++n )
;
@ -2256,11 +2271,12 @@ static int yy_flex_strlen (yyconst char * s )
void *yyalloc (yy_size_t size )
{
return (void *) malloc( size );
return (void *) malloc( size );
}
void *yyrealloc (void * ptr, yy_size_t size )
{
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
* that use void* generic pointers. It works with the latter
@ -2273,12 +2289,12 @@ void *yyrealloc (void * ptr, yy_size_t size )
void yyfree (void * ptr )
{
free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
}
#define YYTABLES_NAME "yytables"
#line 228 "tokenizer.lex"
#line 229 "tokenizer.lex"

290
sol.h

@ -10,7 +10,7 @@
#include "dsl/dsl.h"
/** The version of the project, as made available through `debug.version`. */
#define VERSION "0.2a0"
#define VERSION "0.2a1"
/** The hexadecimal version of the project, formatted 0xAAIIRPP where:
*
* - AA is the two-digit major version
@ -20,7 +20,7 @@
*
* This value is guaranteed to always increase by revision.
*/
#define HEXVER 0x0002A00
#define HEXVER 0x0002A01
#ifndef SOL_ICACHE_MIN
/** The smallest integer to cache. */
@ -380,111 +380,327 @@ typedef struct sol_tag_object_t {
typedef enum {SF_NORMAL, SF_BREAKING, SF_CONTINUING} sol_state_flag_t;
typedef struct sol_tag_state_t {
sol_object_t *scopes; // A list of scope maps, innermost out, ending at the global scope
sol_object_t *ret; // Return value of this function, for early return
sol_object_t *traceback; // The last stack of statement (nodes) in the last error, or NULL
sol_state_flag_t sflag; // Used to implement break/continue
sol_object_t *error; // Some arbitrary error descriptor, None if no error
sol_object_t *stdout; // Standard output stream object (for print())
sol_object_t *stdin; // Standard input stream object
sol_object_t *stderr; // Standard error stream object
sol_object_t *None;
sol_object_t *OutOfMemory;
sol_object_t *StopIteration;
sol_ops_t NullOps;
sol_ops_t SingletOps;
sol_ops_t IntOps;
sol_ops_t FloatOps;
sol_ops_t StringOps;
sol_ops_t ListOps;
sol_ops_t MapOps;
sol_ops_t MCellOps;
sol_ops_t FuncOps;
sol_ops_t CFuncOps;
sol_ops_t ASTNodeOps;
sol_ops_t BufferOps;
sol_ops_t DyLibOps;
sol_ops_t DySymOps;
sol_ops_t StreamOps;
sol_object_t *modules;
sol_object_t *methods;
dsl_object_funcs obfuncs;
const char *calling_type;
const char *calling_meth;
sol_object_t *scopes; ///< A list of scope maps, innermost out, ending at the global scope
sol_object_t *ret; ///< Return value of this function, for early return
sol_object_t *traceback; ///< The last stack of statement (nodes) in the last error, or NULL
sol_state_flag_t sflag; ///< Used to implement break/continue
sol_object_t *error; ///< Some arbitrary error descriptor, `None` if no error
sol_object_t *stdout; ///< Standard output stream object (for print(), type `SOL_STREAM`)
sol_object_t *stdin; ///< Standard input stream object (type `SOL_STREAM`)
sol_object_t *stderr; ///< Standard error stream object (type `SOL_STREAM`)
sol_object_t *None; ///< The all-important `None` object
sol_object_t *OutOfMemory; ///< The semi-important `OutOfMemory` object
sol_object_t *StopIteration; ///< The somewhat-important `StopIteration` object
sol_ops_t NullOps; ///< Basic, initialized operations. Not used by any extant object type.
sol_ops_t SingletOps; ///< Operations on singlets (`None`, `OutOfMemory`, `StopIteration`, etc.)
sol_ops_t IntOps; ///< Operations on integers
sol_ops_t FloatOps; ///< Operations on floats
sol_ops_t StringOps; ///< Operations on strings
sol_ops_t ListOps; ///< Operations on lists
sol_ops_t MapOps; ///< Operations on maps
sol_ops_t MCellOps; ///< Operations on map cells (rarely used)
sol_ops_t FuncOps; ///< Operations on functions
sol_ops_t CFuncOps; ///< Operations on C functions
sol_ops_t ASTNodeOps; ///< Operations on AST nodes
sol_ops_t BufferOps; ///< Operations on buffers
sol_ops_t DyLibOps; ///< Operations on dynamic library objects
sol_ops_t DySymOps; ///< Operations on dynamic symbol objects
sol_ops_t StreamOps; ///< Operations on streams
sol_object_t *modules; ///< A map of modules, string name to contents, resolved at "super-global" scope (and thus overrideable)
sol_object_t *methods; ///< A map of string names to methods (like "list" -> {insert=<CFunction>, remove=<CFunction>, ...}) free for private use by extension developers
dsl_object_funcs obfuncs; ///< The set of object functions that allows DSL to integrate with Sol's reference counting
const char *calling_type; ///< Set (during `CALL_METHOD`) to determine the type (ops structure) being invoked for this method (mostly for sol_f_not_impl)
const char *calling_meth; ///< Set (during `CALL_METHOD`) to determine the method name being invoked (mostly for sol_f_not_impl)
#ifdef SOL_ICACHE
sol_object_t *icache[SOL_ICACHE_MAX - SOL_ICACHE_MIN + 1];
char icache_bypass;
sol_object_t *icache[SOL_ICACHE_MAX - SOL_ICACHE_MIN + 1]; ///< The integer cache (holds integers from `SOL_ICACHE_MIN` to `SOL_ICACHE_MAX` indexed by `[i - SOL_ICACHE_MIN]`)
char icache_bypass; ///< Set to true to bypass caching--needed to avoid infinite recursion when initially populating the cache
#endif
sol_object_t *lastvalue;
sol_object_t *loopvalue;
sol_object_t *lastvalue; ///< Holds the value of the last expression evaluated, returned by an `if` expression
sol_object_t *loopvalue; ///< Holds an initially-empty list appended to by `continue <expr>` or set to another object by `break <expr>`
} sol_state_t;
// state.c
/** Initializes the state.
*
* This should be called once (and only once!) for every state; it does the important
* work of ensuring that the state is ready to execute code, including:
*
* - Creating the initial singlet values `None`, `OutOfMemory`, and `StopIteration`,
* - Creating and populating the operations on all internally-defined object types.
* - Initializing all built-in modules and methods.
* - Running any "init.sol" files.
* - Recognizing early-init errors and aborting.
*
* It is the singular, monolithic place where most pre-execution occurs, and language
* developers may thus use it at their discretion. Extension developers should provide
* their own documented initializers, and embedders should do their own initialization
* immediately after calling this function.
*/
int sol_state_init(sol_state_t *);
/** Cleans up the state.
*
* In theory, after calling this, the state should be ready to be released (e.g., freed
* if it was allocated on the heap). Importantly, it should NOT be used for any code
* execution after this call (it WILL segfault).
*/
void sol_state_cleanup(sol_state_t *);
/** Resolve a name.
*
* Technically, a "name" can be anything (any key in a map, more precisely), but the
* runtime (and most sane code) generally depends on names being strings. It is, however,
* emphatically possible to populate the scopes with non-string names--for potential use
* cases, see `programs/monty.sol`
*/
sol_object_t *sol_state_resolve(sol_state_t *, sol_object_t *);
/** Resolve a string name, given as a C string.
*
* This handles the popular case where a C program would like to resolve the value of a
* variable by (string) name. In particular, it handles the memory of doing so properly.
*/
sol_object_t *sol_state_resolve_name(sol_state_t *, const char *);
/** Assign to a global name.
*
* This is rarely used, except in `sol_state_init`. It sets the value of the given name
* (as an object) in the global (outermost) scope. Code execution generally uses the
* local scope instead.
*/
void sol_state_assign(sol_state_t *, sol_object_t *, sol_object_t *);
/** Assign to a global string name, given as a C string.
*
* This is a convenience for `sol_state_assign`, which handles the creation and destruction
* of the Sol string.
*/
void sol_state_assign_name(sol_state_t *, const char *, sol_object_t *);
/** Assign to a local name.
*
* Sets the name to the value in the local (innermost) scope. It has the functional equivalent
* of the Sol code `<name> = <value>` in whatever context the state is in.
*/
void sol_state_assign_l(sol_state_t *, sol_object_t *, sol_object_t *);
/** Assign to a local string name, given as a C string.
*
* Another convenience for `sol_state_assign_l`.
*/
void sol_state_assign_l_name(sol_state_t *, const char *, sol_object_t *);
/** Push a scope.
*
* This adds a new (more-local) scope to the scope stack (`state->scopes`). This permits values
* in such a scope to be manipulated independently of those in enclosing scopes, and their references
* are discarded during the next `sol_state_pop_scope`. (The values may, of course, be present via
* other references.)
*
* Scope stack manipulation MUST be balanced; egregious errors will occur otherwise.
*
* Scope stack manipulation is generally only necessary where another environment is expected for the
* code running in that context; e.g., the body of a function, or an AST node from an imported file. In
* particular, most control structures do NOT introduce scopes, due to the deleterious effects of having
* no direct influence on enclosing scopes.
*/
void sol_state_push_scope(sol_state_t *, sol_object_t *);
/** Pops a scope.
*
* Removes and discards the local scope. All names and associated value references are lost.
*
* This MUST be balanced with `sol_state_push_scope`.
*/
sol_object_t *sol_state_pop_scope(sol_state_t *);
/** Returns the current error.
*
* This object is `None` if there is no error. See `sol_has_error`.
*/
sol_object_t *sol_get_error(sol_state_t *);
/** Set the current error.
*
* Sets the current error object. Clears the error if the object is `None`.
*/
sol_object_t *sol_set_error(sol_state_t *, sol_object_t *);
/** Set the current error to a string, given a C string.
*
* Conveniently sets the error to a string object created from the given C string.
*/
sol_object_t *sol_set_error_string(sol_state_t *, const char *);
/** Clear the current error.
*
* Equivalent to `sol_set_error(state, state->None)`.
*/
void sol_clear_error(sol_state_t *);
/** Prepares a traceback.
*
* Initializes the traceback stack to an empty list in preparation of `sol_add_traceback`.
* Typically used by the runtime while recovering from an error; the value is ultimately
* returned as the third element of the return list from `try`.
*/
void sol_init_traceback(sol_state_t *);
/** Adds an object to a traceback.
*
* This object is usually an ASTNode; typically, it is a statement which was being executed
* when the relevant error occurred. This object is made the first item of the traceback pair
* (the second element is the current local scope).
*/
void sol_add_traceback(sol_state_t *, sol_object_t *);
/** Gets the traceback.
*
* This will be a list of traceback pairs; each such pair will be [<value given to `sol_add_traceback`>,
* <local scope>].
*/
sol_object_t *sol_traceback(sol_state_t *);
/** Registers a module.
*
* Creates a module entry by name, referring to its value. Modules resolve after globals, and
* therefore form a sort of untouchable "super-global" scope. Most built-in modules reside in
* this namespace.
*/
void sol_register_module(sol_state_t *, sol_object_t *, sol_object_t *);
/** Registers a module by string name, given a C string.
*
* A convenience for `sol_register_module`.
*/
void sol_register_module_name(sol_state_t *, char *, sol_object_t *);
/** Gets a module.
*
* Retrieves a module by its given name. Its value will be as it was registered.
*/
sol_object_t *sol_get_module(sol_state_t *, sol_object_t *);
/** Gets a module by string name, given a C string.
*
* A convenience for `sol_get_module`.
*/
sol_object_t *sol_get_module_name(sol_state_t *, char *);
/** Registers methods.
*
* Creates a methods entry by name, referring to its value. Methods are never resolved directly
* by (non-debug) code, but are used liberally throughout the C interface for implementing named
* methods on objects (such as lists, buffers, etc.) that wouldn't normally resolve names--thus
* the name. Thus, the mapping forms a sort of private namespace that may freely be used by
* developers as they see fit.
*/
void sol_register_methods(sol_state_t *, sol_object_t *, sol_object_t *);
/** Registers a method by string name, given a C string.
*
* A convenience for `sol_register_methods`.
*/
void sol_register_methods_name(sol_state_t *, char *, sol_object_t *);
/** Gets methods.
*
* Retrieves the methods by its name, returning the value that was registered.
*/
sol_object_t *sol_get_methods(sol_state_t *, sol_object_t *);
/** Gets methods by string name, given a C string.
*
* A convenience for `sol_get_methods`.
*/
sol_object_t *sol_get_methods_name(sol_state_t *, char *);
/** Index operation override for the `io` module.
*
* This hook virtually provides `stdin`, `stdout`, and `stderr` by returning the relevant
* values on the states.
*/
sol_object_t *sol_f_io_index(sol_state_t *, sol_object_t *);
/** Setindex operation override for the `io` module.
*
* This hook intercepts and specially handles attempts to set `stdin`, `stdout`, and `stderr`
* by setting the relevant values on the state.
*/
sol_object_t *sol_f_io_setindex(sol_state_t *, sol_object_t *);
/** Retrieves the stdin stream.
*
* Returns the stream object used to read program input.
*/
sol_object_t *sol_get_stdin(sol_state_t *);
/** Retrieves the stdout stream.
*
* Returns the stream object used to write program output.
*/
sol_object_t *sol_get_stdout(sol_state_t *);
/** Retrieves the stderr stream.
*
* Returns the stream object used to write program errors or out-of-band data.
*/
sol_object_t *sol_get_stderr(sol_state_t *);
/** Initializes an ops structure.
*
* This sets all the fields of a `sol_ops_t` to their sensible defaults. Such an initialized
* structure is available on the state as `state->NullOps`.
*/
void sol_ops_init(sol_ops_t *);
// builtins.c
/** Not implemented handler.
*
* This raises the "Undefined method" error.
*/
sol_object_t *sol_f_not_impl(sol_state_t *, sol_object_t *);
/** !!! handler.
*
* Swaps objects by value.
*/
sol_object_t *sol_f_tbang(sol_state_t *, sol_object_t *);
/** No operation handler.
*
* Does nothing.
*/
sol_object_t *sol_f_no_op(sol_state_t *, sol_object_t *);
/** Default comparison handler.
*
* Returns 0 (equal) if the references refer to exactly the same object, or
* 1 (greater) otherwise.
*
* Note that this is not a partial order.
*/
sol_object_t *sol_f_default_cmp(sol_state_t *, sol_object_t *);
/** Default tostring handler.
*
* Returns a string formatted as "<<typename> object at <address>>".
*/
sol_object_t *sol_f_default_tostring(sol_state_t *, sol_object_t *);
/** Default torepr handler.
*
* Returns tostring(object).
*/
sol_object_t *sol_f_default_repr(sol_state_t *, sol_object_t *);
/// Built-in function toint
sol_object_t *sol_f_toint(sol_state_t *, sol_object_t *);
/// Built-in function tofloat
sol_object_t *sol_f_tofloat(sol_state_t *, sol_object_t *);
/// Built-in function tostring
sol_object_t *sol_f_tostring(sol_state_t *, sol_object_t *);
/// Built-in function try
sol_object_t *sol_f_try(sol_state_t *, sol_object_t *);
/// Built-in function error
sol_object_t *sol_f_error(sol_state_t *, sol_object_t *);
/// Built-in function type
sol_object_t *sol_f_type(sol_state_t *, sol_object_t *);
/// Built-in function prepr
sol_object_t *sol_f_prepr(sol_state_t *, sol_object_t *);
/// Built-in function print
sol_object_t *sol_f_print(sol_state_t *, sol_object_t *);
/// Built-in function rawget
sol_object_t *sol_f_rawget(sol_state_t *, sol_object_t *);
/// Built-in function rawset
sol_object_t *sol_f_rawset(sol_state_t *, sol_object_t *);
/// Built-in function range
sol_object_t *sol_f_range(sol_state_t *, sol_object_t *);
/// Built-in function exec
sol_object_t *sol_f_exec(sol_state_t *, sol_object_t *);
/// Built-in function eval
sol_object_t *sol_f_eval(sol_state_t *, sol_object_t *);
/// Built-in function execfile
sol_object_t *sol_f_execfile(sol_state_t *, sol_object_t *);
/// Built-in function parse
sol_object_t *sol_f_parse(sol_state_t *, sol_object_t *);
/// Built-in function ord
sol_object_t *sol_f_ord(sol_state_t *, sol_object_t *);
/// Built-in function chr
sol_object_t *sol_f_chr(sol_state_t *, sol_object_t *);
sol_object_t *sol_f_debug_getref(sol_state_t *, sol_object_t *);

53
state.c

@ -1,11 +1,31 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ast.h"
#define TMP_PATH_SZ 256
char *sol_AbsInitPaths[] = {
"/etc/sol/init.sol",
"/opt/sol/init.sol",
};
char *sol_HomeInitPaths[] = {
"/.config/sol/init.sol",
};
char sol_TempPath[TMP_PATH_SZ];
#define LENGTH(array) (sizeof(array) / sizeof(array[0]))
int sol_state_init(sol_state_t *state) {
sol_object_t *globals, *mod, *meths;
sol_object_t *btype, *bsize, *bobj;
unsigned long i;
FILE *fp;
stmt_node *stmt;
char *suffix;
sol_mm_initialize(state);
@ -445,6 +465,39 @@ int sol_state_init(sol_state_t *state) {
goto cleanup;
}
// Perform initialization based on the user profile, if so requested.
// TODO: Make this switchable at runtime.
for(i = 0; i < LENGTH(sol_AbsInitPaths); i++) {
fp = fopen(sol_AbsInitPaths[i], "r");
if(fp) {
stmt = sol_compile_file(fp);
sol_exec(state, stmt);
st_free(stmt);
fclose(fp);
}
}
suffix = getenv("HOME");
if(suffix) {
strncpy(sol_TempPath, suffix, TMP_PATH_SZ);
suffix = sol_TempPath + strlen(sol_TempPath);
for(i = 0; i < LENGTH(sol_HomeInitPaths); i++) {
strncpy(suffix, sol_HomeInitPaths[i], TMP_PATH_SZ - (suffix - sol_TempPath));
fp = fopen(sol_TempPath, "r");
if(fp) {
stmt = sol_compile_file(fp);
sol_exec(state, stmt);
st_free(stmt);
fclose(fp);
}
}
}
if(sol_has_error(state)) {
goto cleanup;
}
// We're all set!
return 1;

Loading…
Cancel
Save