2017-12-03 17:52:09 +00:00
/*
2023-01-07 21:03:35 +00:00
* Copyright ( c ) 2023 Calvin Rose
2017-12-03 17:52:09 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to
* deal in the Software without restriction , including without limitation the
* rights to use , copy , modify , merge , publish , distribute , sublicense , and / or
* sell copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE .
*/
2019-01-24 05:15:58 +00:00
# ifndef JANET_AMALG
2019-12-31 00:06:15 +00:00
# include "features.h"
2019-02-19 01:13:35 +00:00
# include <janet.h>
2017-12-15 00:33:45 +00:00
# include "compile.h"
2018-07-01 15:52:15 +00:00
# include "emit.h"
2018-07-04 03:07:35 +00:00
# include "vector.h"
2019-01-06 06:49:56 +00:00
# include "util.h"
2019-05-20 15:34:07 +00:00
# include "state.h"
2019-01-24 05:15:58 +00:00
# endif
2017-12-03 17:52:09 +00:00
2018-09-06 02:18:42 +00:00
JanetFopts janetc_fopts_default ( JanetCompiler * c ) {
JanetFopts ret ;
2018-01-17 04:18:45 +00:00
ret . compiler = c ;
ret . flags = 0 ;
2018-09-06 02:18:42 +00:00
ret . hint = janetc_cslot ( janet_wrap_nil ( ) ) ;
2018-01-17 04:18:45 +00:00
return ret ;
}
2018-09-06 02:18:42 +00:00
/* Throw an error with a janet string. */
void janetc_error ( JanetCompiler * c , const uint8_t * m ) {
2018-01-05 21:17:55 +00:00
/* Don't override first error */
2018-09-06 02:18:42 +00:00
if ( c - > result . status = = JANET_COMPILE_ERROR ) {
2018-01-05 21:17:55 +00:00
return ;
}
2018-09-06 02:18:42 +00:00
c - > result . status = JANET_COMPILE_ERROR ;
2017-12-30 21:46:59 +00:00
c - > result . error = m ;
2017-12-15 00:33:45 +00:00
}
2017-12-16 06:17:53 +00:00
/* Throw an error with a message in a cstring */
2018-09-06 02:18:42 +00:00
void janetc_cerror ( JanetCompiler * c , const char * m ) {
janetc_error ( c , janet_cstring ( m ) ) ;
2017-12-15 00:33:45 +00:00
}
2017-12-21 04:03:34 +00:00
2021-05-28 20:12:05 +00:00
static const char * janet_lint_level_names [ ] = {
" relaxed " ,
" normal " ,
" strict "
} ;
/* Emit compiler linter messages */
void janetc_lintf ( JanetCompiler * c , JanetCompileLintLevel level , const char * format , . . . ) {
if ( NULL ! = c - > lints ) {
/* format message */
va_list args ;
JanetBuffer buffer ;
int32_t len = 0 ;
while ( format [ len ] ) len + + ;
janet_buffer_init ( & buffer , len ) ;
va_start ( args , format ) ;
janet_formatbv ( & buffer , format , args ) ;
va_end ( args ) ;
const uint8_t * str = janet_string ( buffer . data , buffer . count ) ;
janet_buffer_deinit ( & buffer ) ;
/* construct linting payload */
Janet * payload = janet_tuple_begin ( 4 ) ;
payload [ 0 ] = janet_ckeywordv ( janet_lint_level_names [ level ] ) ;
2021-05-30 15:33:46 +00:00
payload [ 1 ] = c - > current_mapping . line = = - 1 ? janet_wrap_nil ( ) : janet_wrap_integer ( c - > current_mapping . line ) ;
payload [ 2 ] = c - > current_mapping . column = = - 1 ? janet_wrap_nil ( ) : janet_wrap_integer ( c - > current_mapping . column ) ;
2021-05-28 20:12:05 +00:00
payload [ 3 ] = janet_wrap_string ( str ) ;
janet_array_push ( c - > lints , janet_wrap_tuple ( janet_tuple_end ( payload ) ) ) ;
}
}
2017-12-21 04:03:34 +00:00
/* Free a slot */
2018-09-06 02:18:42 +00:00
void janetc_freeslot ( JanetCompiler * c , JanetSlot s ) {
if ( s . flags & ( JANET_SLOT_CONSTANT | JANET_SLOT_REF | JANET_SLOT_NAMED ) ) return ;
2018-02-12 21:43:59 +00:00
if ( s . envindex > = 0 ) return ;
2018-09-06 02:18:42 +00:00
janetc_regalloc_free ( & c - > scope - > ra , s . index ) ;
2017-12-21 04:03:34 +00:00
}
/* Add a slot to a scope with a symbol associated with it (def or var). */
2018-09-06 02:18:42 +00:00
void janetc_nameslot ( JanetCompiler * c , const uint8_t * sym , JanetSlot s ) {
2018-01-05 21:17:55 +00:00
SymPair sp ;
sp . sym = sym ;
sp . slot = s ;
2018-01-21 19:39:32 +00:00
sp . keep = 0 ;
2018-09-06 02:18:42 +00:00
sp . slot . flags | = JANET_SLOT_NAMED ;
2023-02-01 08:39:24 +00:00
// -1 because c->buffer has already passed the `def`/`var`
sp . bytecode_pos = janet_v_count ( c - > buffer ) - 1 ;
2018-09-06 02:18:42 +00:00
janet_v_push ( c - > scope - > syms , sp ) ;
2018-07-01 15:52:15 +00:00
}
/* Create a slot with a constant */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_cslot ( Janet x ) {
JanetSlot ret ;
ret . flags = ( 1 < < janet_type ( x ) ) | JANET_SLOT_CONSTANT ;
2018-07-01 15:52:15 +00:00
ret . index = - 1 ;
ret . constant = x ;
ret . envindex = - 1 ;
return ret ;
}
2018-07-04 03:07:35 +00:00
/* Get a local slot */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_farslot ( JanetCompiler * c ) {
JanetSlot ret ;
ret . flags = JANET_SLOTTYPE_ANY ;
ret . index = janetc_allocfar ( c ) ;
ret . constant = janet_wrap_nil ( ) ;
2018-07-01 15:52:15 +00:00
ret . envindex = - 1 ;
return ret ;
2017-12-21 04:03:34 +00:00
}
/* Enter a new scope */
2018-09-06 02:18:42 +00:00
void janetc_scope ( JanetScope * s , JanetCompiler * c , int flags , const char * name ) {
JanetScope scope ;
2018-07-01 15:52:15 +00:00
scope . name = name ;
scope . child = NULL ;
2018-01-05 21:17:55 +00:00
scope . consts = NULL ;
scope . syms = NULL ;
scope . envs = NULL ;
scope . defs = NULL ;
2018-09-06 02:18:42 +00:00
scope . bytecode_start = janet_v_count ( c - > buffer ) ;
2018-01-05 21:17:55 +00:00
scope . flags = flags ;
2018-09-10 18:54:12 +00:00
scope . parent = c - > scope ;
2020-03-18 14:30:10 +00:00
janetc_regalloc_init ( & scope . ua ) ;
2018-01-04 02:36:10 +00:00
/* Inherit slots */
2018-09-06 02:18:42 +00:00
if ( ( ! ( flags & JANET_SCOPE_FUNCTION ) ) & & c - > scope ) {
2018-09-10 18:54:12 +00:00
janetc_regalloc_clone ( & scope . ra , & ( c - > scope - > ra ) ) ;
2018-07-01 15:52:15 +00:00
} else {
2018-09-10 18:54:12 +00:00
janetc_regalloc_init ( & scope . ra ) ;
2018-01-04 02:36:10 +00:00
}
2018-07-01 15:52:15 +00:00
/* Link parent and child and update pointer */
if ( c - > scope )
c - > scope - > child = s ;
c - > scope = s ;
2018-09-10 18:54:12 +00:00
* s = scope ;
2017-12-15 00:33:45 +00:00
}
2017-12-16 06:17:53 +00:00
/* Leave a scope. */
2018-09-06 02:18:42 +00:00
void janetc_popscope ( JanetCompiler * c ) {
JanetScope * oldscope = c - > scope ;
JanetScope * newscope = oldscope - > parent ;
2018-01-06 16:09:15 +00:00
/* Move free slots to parent scope if not a new function.
* We need to know the total number of slots used when compiling the function . */
2018-09-06 02:18:42 +00:00
if ( ! ( oldscope - > flags & ( JANET_SCOPE_FUNCTION | JANET_SCOPE_UNUSED ) ) & & newscope ) {
2018-07-12 01:29:39 +00:00
/* Parent scopes inherit child's closure flag. Needed
* for while loops . ( if a while loop creates a closure , it
* is compiled to a tail recursive iife ) */
2018-09-06 02:18:42 +00:00
if ( oldscope - > flags & JANET_SCOPE_CLOSURE ) {
newscope - > flags | = JANET_SCOPE_CLOSURE ;
2018-07-12 01:29:39 +00:00
}
2018-07-01 15:52:15 +00:00
if ( newscope - > ra . max < oldscope - > ra . max )
newscope - > ra . max = oldscope - > ra . max ;
2018-01-21 19:39:32 +00:00
/* Keep upvalue slots */
2018-09-06 02:18:42 +00:00
for ( int32_t i = 0 ; i < janet_v_count ( oldscope - > syms ) ; i + + ) {
2018-07-01 15:52:15 +00:00
SymPair pair = oldscope - > syms [ i ] ;
2018-01-21 19:39:32 +00:00
if ( pair . keep ) {
/* The variable should not be lexically accessible */
pair . sym = NULL ;
2018-09-06 02:18:42 +00:00
janet_v_push ( newscope - > syms , pair ) ;
janetc_regalloc_touch ( & newscope - > ra , pair . slot . index ) ;
2018-01-21 19:39:32 +00:00
}
}
2023-02-01 08:39:24 +00:00
}
if ( janet_truthy ( janet_dyn ( " debug " ) ) ) {
2023-02-01 10:06:33 +00:00
bool top_level = ( oldscope - > flags & ( JANET_SCOPE_FUNCTION | JANET_SCOPE_UNUSED ) ) ;
/* push symbol slots */
JanetSymbolSlot ss ;
int32_t scope_end = top_level ? INT32_MAX : janet_v_count ( c - > buffer ) ;
2023-02-01 08:39:24 +00:00
2023-02-01 10:06:33 +00:00
janet_assert ( janet_v_count ( c - > local_symbols ) > 0 , " c->local_symbols should not be empty " ) ;
2023-02-01 08:39:24 +00:00
2023-02-01 10:06:33 +00:00
// due to scopes being added "in reverse" (filo), we will reverse all symbols later. therefore we must first reverse the order of symbols inside each scope as well.
for ( int32_t i = janet_v_count ( oldscope - > syms ) - 1 ; i > = 0 ; i - - ) {
SymPair pair = oldscope - > syms [ i ] ;
2023-02-01 08:39:24 +00:00
2023-02-01 10:06:33 +00:00
if ( pair . sym ! = NULL ) {
ss . birth_pc = pair . bytecode_pos ;
ss . death_pc = scope_end ;
ss . slot_index = pair . slot . index ;
ss . symbol = pair . sym ;
2018-01-21 19:39:32 +00:00
2023-02-01 10:06:33 +00:00
janet_v_push ( janet_v_last ( c - > local_symbols ) , ss ) ;
2023-02-01 08:39:24 +00:00
}
}
2018-01-06 16:09:15 +00:00
}
2023-02-01 08:39:24 +00:00
2018-07-01 15:52:15 +00:00
/* Free the old scope */
2018-09-06 02:18:42 +00:00
janet_v_free ( oldscope - > consts ) ;
janet_v_free ( oldscope - > syms ) ;
janet_v_free ( oldscope - > envs ) ;
janet_v_free ( oldscope - > defs ) ;
janetc_regalloc_deinit ( & oldscope - > ra ) ;
2020-03-18 14:30:10 +00:00
janetc_regalloc_deinit ( & oldscope - > ua ) ;
2018-07-01 15:52:15 +00:00
/* Update pointer */
if ( newscope )
newscope - > child = NULL ;
c - > scope = newscope ;
2017-12-15 00:33:45 +00:00
}
2018-01-16 04:31:39 +00:00
/* Leave a scope but keep a slot allocated. */
2018-09-06 02:18:42 +00:00
void janetc_popscope_keepslot ( JanetCompiler * c , JanetSlot retslot ) {
JanetScope * scope ;
janetc_popscope ( c ) ;
2018-07-01 15:52:15 +00:00
scope = c - > scope ;
if ( scope & & retslot . envindex < 0 & & retslot . index > = 0 ) {
2018-09-06 02:18:42 +00:00
janetc_regalloc_touch ( & scope - > ra , retslot . index ) ;
2018-01-16 04:31:39 +00:00
}
}
2022-01-24 02:08:33 +00:00
static int lookup_missing (
JanetCompiler * c ,
const uint8_t * sym ,
JanetFunction * handler ,
2022-01-28 03:24:01 +00:00
JanetBinding * out ) {
int32_t minar = handler - > def - > min_arity ;
int32_t maxar = handler - > def - > max_arity ;
if ( minar > 1 | | maxar < 1 ) {
janetc_error ( c , janet_cstring ( " missing symbol lookup handler must take 1 argument " ) ) ;
return 0 ;
}
Janet args [ 1 ] = { janet_wrap_symbol ( sym ) } ;
JanetFiber * fiberp = janet_fiber ( handler , 64 , 1 , args ) ;
2022-01-24 02:08:33 +00:00
if ( NULL = = fiberp ) {
2022-01-28 03:24:01 +00:00
janetc_error ( c , janet_cstring ( " failed to call missing symbol lookup handler " ) ) ;
2022-01-24 02:08:33 +00:00
return 0 ;
}
fiberp - > env = c - > env ;
int lock = janet_gclock ( ) ;
Janet tempOut ;
JanetSignal status = janet_continue ( fiberp , janet_wrap_nil ( ) , & tempOut ) ;
janet_gcunlock ( lock ) ;
if ( status ! = JANET_SIGNAL_OK ) {
janetc_error ( c , janet_formatc ( " (lookup) %V " , tempOut ) ) ;
return 0 ;
}
2022-01-28 03:24:01 +00:00
/* Convert return value as entry. */
/* Alternative could use janet_resolve_ext(c->env, sym) to read result from environment. */
* out = janet_binding_from_entry ( tempOut ) ;
2022-01-24 02:08:33 +00:00
return 1 ;
}
2017-12-15 00:33:45 +00:00
/* Allow searching for symbols. Return information about the symbol */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_resolve (
2019-02-20 01:51:34 +00:00
JanetCompiler * c ,
const uint8_t * sym ) {
2017-12-15 00:33:45 +00:00
2018-09-06 02:18:42 +00:00
JanetSlot ret = janetc_cslot ( janet_wrap_nil ( ) ) ;
JanetScope * scope = c - > scope ;
2018-01-21 19:39:32 +00:00
SymPair * pair ;
2017-12-16 06:17:53 +00:00
int foundlocal = 1 ;
2018-01-04 02:36:10 +00:00
int unused = 0 ;
2017-12-15 00:33:45 +00:00
/* Search scopes for symbol, starting from top */
2018-07-01 15:52:15 +00:00
while ( scope ) {
2018-01-05 21:17:55 +00:00
int32_t i , len ;
2018-09-06 02:18:42 +00:00
if ( scope - > flags & JANET_SCOPE_UNUSED )
2018-01-04 02:36:10 +00:00
unused = 1 ;
2018-09-06 02:18:42 +00:00
len = janet_v_count ( scope - > syms ) ;
2018-01-29 20:46:26 +00:00
/* Search in reverse order */
for ( i = len - 1 ; i > = 0 ; i - - ) {
2018-01-21 19:39:32 +00:00
pair = scope - > syms + i ;
if ( pair - > sym = = sym ) {
ret = pair - > slot ;
2018-01-05 21:17:55 +00:00
goto found ;
}
}
2018-09-06 02:18:42 +00:00
if ( scope - > flags & JANET_SCOPE_FUNCTION )
2017-12-16 06:17:53 +00:00
foundlocal = 0 ;
2018-07-01 15:52:15 +00:00
scope = scope - > parent ;
2017-12-15 00:33:45 +00:00
}
2017-12-21 04:03:34 +00:00
/* Symbol not found - check for global */
2018-01-05 21:17:55 +00:00
{
2021-05-28 20:12:05 +00:00
JanetBinding binding = janet_resolve_ext ( c - > env , sym ) ;
2022-01-24 02:08:33 +00:00
if ( binding . type = = JANET_BINDING_NONE ) {
Janet handler = janet_table_get ( c - > env , janet_ckeywordv ( " missing-symbol " ) ) ;
switch ( janet_type ( handler ) ) {
case JANET_NIL :
break ;
case JANET_FUNCTION :
2022-01-28 03:24:01 +00:00
if ( ! lookup_missing ( c , sym , janet_unwrap_function ( handler ) , & binding ) )
2022-01-24 02:08:33 +00:00
return janetc_cslot ( janet_wrap_nil ( ) ) ;
break ;
default :
janetc_error ( c , janet_formatc ( " invalid lookup handler %V " , handler ) ) ;
return janetc_cslot ( janet_wrap_nil ( ) ) ;
}
}
2021-05-28 20:12:05 +00:00
switch ( binding . type ) {
2018-06-17 17:55:02 +00:00
default :
2018-09-06 02:18:42 +00:00
case JANET_BINDING_NONE :
2020-02-27 23:58:17 +00:00
janetc_error ( c , janet_formatc ( " unknown symbol %q " , janet_wrap_symbol ( sym ) ) ) ;
2018-09-06 02:18:42 +00:00
return janetc_cslot ( janet_wrap_nil ( ) ) ;
case JANET_BINDING_DEF :
case JANET_BINDING_MACRO : /* Macro should function like defs when not in calling pos */
2021-05-28 20:12:05 +00:00
ret = janetc_cslot ( binding . value ) ;
2022-01-07 01:44:03 +00:00
break ;
case JANET_BINDING_DYNAMIC_DEF :
case JANET_BINDING_DYNAMIC_MACRO :
ret = janetc_cslot ( binding . value ) ;
ret . flags | = JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOTTYPE_ANY ;
ret . flags & = ~ JANET_SLOT_CONSTANT ;
2021-12-18 04:05:16 +00:00
break ;
2019-02-20 01:51:34 +00:00
case JANET_BINDING_VAR : {
2021-05-28 20:12:05 +00:00
ret = janetc_cslot ( binding . value ) ;
2018-09-06 02:18:42 +00:00
ret . flags | = JANET_SLOT_REF | JANET_SLOT_NAMED | JANET_SLOT_MUTABLE | JANET_SLOTTYPE_ANY ;
ret . flags & = ~ JANET_SLOT_CONSTANT ;
2021-05-28 20:12:05 +00:00
break ;
2018-06-17 17:55:02 +00:00
}
2018-01-05 21:17:55 +00:00
}
2021-05-28 20:12:05 +00:00
JanetCompileLintLevel depLevel = JANET_C_LINT_RELAXED ;
switch ( binding . deprecation ) {
case JANET_BINDING_DEP_NONE :
break ;
case JANET_BINDING_DEP_RELAXED :
depLevel = JANET_C_LINT_RELAXED ;
break ;
case JANET_BINDING_DEP_NORMAL :
depLevel = JANET_C_LINT_NORMAL ;
break ;
case JANET_BINDING_DEP_STRICT :
depLevel = JANET_C_LINT_STRICT ;
break ;
}
if ( binding . deprecation ! = JANET_BINDING_DEP_NONE ) {
janetc_lintf ( c , depLevel , " %q is deprecated " , janet_wrap_symbol ( sym ) ) ;
}
return ret ;
2018-01-05 21:17:55 +00:00
}
2017-12-15 00:33:45 +00:00
/* Symbol was found */
2019-02-20 01:51:34 +00:00
found :
2017-12-15 00:33:45 +00:00
2017-12-16 06:17:53 +00:00
/* Constants can be returned immediately (they are stateless) */
2018-09-06 02:18:42 +00:00
if ( ret . flags & ( JANET_SLOT_CONSTANT | JANET_SLOT_REF ) )
2018-01-04 02:36:10 +00:00
return ret ;
/* Unused references and locals shouldn't add captured envs. */
if ( unused | | foundlocal ) {
2018-02-12 21:43:59 +00:00
ret . envindex = - 1 ;
2017-12-15 00:33:45 +00:00
return ret ;
2018-01-04 02:36:10 +00:00
}
2017-12-15 00:33:45 +00:00
/* non-local scope needs to expose its environment */
2018-01-21 19:39:32 +00:00
pair - > keep = 1 ;
2018-09-06 02:18:42 +00:00
while ( scope & & ! ( scope - > flags & JANET_SCOPE_FUNCTION ) )
2018-07-01 15:52:15 +00:00
scope = scope - > parent ;
2018-09-06 02:18:42 +00:00
janet_assert ( scope , " invalid scopes " ) ;
scope - > flags | = JANET_SCOPE_ENV ;
2020-03-18 14:30:10 +00:00
/* In the function scope, allocate the slot as an upvalue */
janetc_regalloc_touch ( & scope - > ua , ret . index ) ;
/* Iterate through child scopes and make sure environment is propagated */
2018-07-01 15:52:15 +00:00
scope = scope - > child ;
2017-12-15 00:33:45 +00:00
2019-01-06 08:23:03 +00:00
/* Propagate env up to current scope */
2018-02-12 21:43:59 +00:00
int32_t envindex = - 1 ;
2018-07-01 15:52:15 +00:00
while ( scope ) {
2018-09-06 02:18:42 +00:00
if ( scope - > flags & JANET_SCOPE_FUNCTION ) {
2018-01-05 21:17:55 +00:00
int32_t j , len ;
2017-12-16 06:17:53 +00:00
int scopefound = 0 ;
/* Check if scope already has env. If so, break */
2018-09-06 02:18:42 +00:00
len = janet_v_count ( scope - > envs ) ;
2018-02-12 21:43:59 +00:00
for ( j = 0 ; j < len ; j + + ) {
2017-12-21 04:03:34 +00:00
if ( scope - > envs [ j ] = = envindex ) {
2017-12-16 06:17:53 +00:00
scopefound = 1 ;
2017-12-21 04:03:34 +00:00
envindex = j ;
2017-12-16 06:17:53 +00:00
break ;
}
2017-12-15 00:33:45 +00:00
}
2017-12-21 04:03:34 +00:00
/* Add the environment if it is not already referenced */
2018-01-05 21:17:55 +00:00
if ( ! scopefound ) {
2018-09-06 02:18:42 +00:00
len = janet_v_count ( scope - > envs ) ;
janet_v_push ( scope - > envs , envindex ) ;
2018-01-05 21:17:55 +00:00
envindex = len ;
}
2017-12-15 00:33:45 +00:00
}
2018-07-01 15:52:15 +00:00
scope = scope - > child ;
2017-12-15 00:33:45 +00:00
}
2018-05-20 01:16:00 +00:00
2017-12-21 04:03:34 +00:00
ret . envindex = envindex ;
2017-12-15 00:33:45 +00:00
return ret ;
}
2017-12-17 04:11:51 +00:00
/* Generate the return instruction for a slot. */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_return ( JanetCompiler * c , JanetSlot s ) {
if ( ! ( s . flags & JANET_SLOT_RETURNED ) ) {
if ( s . flags & JANET_SLOT_CONSTANT & & janet_checktype ( s . constant , JANET_NIL ) )
janetc_emit ( c , JOP_RETURN_NIL ) ;
2018-07-01 15:52:15 +00:00
else
2018-09-06 02:18:42 +00:00
janetc_emit_s ( c , JOP_RETURN , s , 0 ) ;
s . flags | = JANET_SLOT_RETURNED ;
2017-12-17 04:11:51 +00:00
}
2018-01-04 02:36:10 +00:00
return s ;
2017-12-17 04:11:51 +00:00
}
2018-07-04 03:07:35 +00:00
/* Get a target slot for emitting an instruction. */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_gettarget ( JanetFopts opts ) {
JanetSlot slot ;
if ( ( opts . flags & JANET_FOPTS_HINT ) & &
2019-02-20 01:51:34 +00:00
( opts . hint . envindex < 0 ) & &
( opts . hint . index > = 0 & & opts . hint . index < = 0xFF ) ) {
2018-01-04 02:36:10 +00:00
slot = opts . hint ;
} else {
2018-02-12 21:43:59 +00:00
slot . envindex = - 1 ;
2018-09-06 02:18:42 +00:00
slot . constant = janet_wrap_nil ( ) ;
2018-01-04 02:36:10 +00:00
slot . flags = 0 ;
2018-09-06 02:18:42 +00:00
slot . index = janetc_allocfar ( opts . compiler ) ;
2017-12-21 04:03:34 +00:00
}
2018-01-04 02:36:10 +00:00
return slot ;
2017-12-21 04:03:34 +00:00
}
2018-01-05 21:17:55 +00:00
/* Get a bunch of slots for function arguments */
2018-09-06 02:18:42 +00:00
JanetSlot * janetc_toslots ( JanetCompiler * c , const Janet * vals , int32_t len ) {
2018-01-17 04:18:45 +00:00
int32_t i ;
2018-09-06 02:18:42 +00:00
JanetSlot * ret = NULL ;
JanetFopts subopts = janetc_fopts_default ( c ) ;
2018-01-17 04:18:45 +00:00
for ( i = 0 ; i < len ; i + + ) {
2018-09-06 02:18:42 +00:00
janet_v_push ( ret , janetc_value ( subopts , vals [ i ] ) ) ;
2018-01-05 21:17:55 +00:00
}
return ret ;
}
2017-12-21 04:03:34 +00:00
2018-01-05 21:17:55 +00:00
/* Get a bunch of slots for function arguments */
2018-09-06 02:18:42 +00:00
JanetSlot * janetc_toslotskv ( JanetCompiler * c , Janet ds ) {
JanetSlot * ret = NULL ;
JanetFopts subopts = janetc_fopts_default ( c ) ;
const JanetKV * kvs = NULL ;
2019-03-23 17:50:50 +00:00
int32_t cap = 0 , len = 0 ;
2018-09-06 02:18:42 +00:00
janet_dictionary_view ( ds , & kvs , & len , & cap ) ;
2019-03-23 17:50:50 +00:00
for ( int32_t i = 0 ; i < cap ; i + + ) {
2018-09-06 02:18:42 +00:00
if ( janet_checktype ( kvs [ i ] . key , JANET_NIL ) ) continue ;
janet_v_push ( ret , janetc_value ( subopts , kvs [ i ] . key ) ) ;
janet_v_push ( ret , janetc_value ( subopts , kvs [ i ] . value ) ) ;
2018-01-05 21:17:55 +00:00
}
return ret ;
}
2017-12-21 04:03:34 +00:00
2019-10-01 00:59:35 +00:00
/* Push slots loaded via janetc_toslots. Return the minimum number of slots pushed,
2019-10-01 00:50:42 +00:00
* or - 1 - min_arity if there is a splice . ( if there is no splice , min_arity is also
* the maximum possible arity ) . */
int32_t janetc_pushslots ( JanetCompiler * c , JanetSlot * slots ) {
2018-01-05 21:17:55 +00:00
int32_t i ;
2018-12-05 20:10:04 +00:00
int32_t count = janet_v_count ( slots ) ;
2019-10-01 00:50:42 +00:00
int32_t min_arity = 0 ;
int has_splice = 0 ;
2018-12-05 20:10:04 +00:00
for ( i = 0 ; i < count ; ) {
if ( slots [ i ] . flags & JANET_SLOT_SPLICED ) {
janetc_emit_s ( c , JOP_PUSH_ARRAY , slots [ i ] , 0 ) ;
i + + ;
2019-10-01 00:50:42 +00:00
has_splice = 1 ;
2018-12-05 20:10:04 +00:00
} else if ( i + 1 = = count ) {
janetc_emit_s ( c , JOP_PUSH , slots [ i ] , 0 ) ;
i + + ;
2019-10-01 00:50:42 +00:00
min_arity + + ;
2018-12-05 20:10:04 +00:00
} else if ( slots [ i + 1 ] . flags & JANET_SLOT_SPLICED ) {
janetc_emit_s ( c , JOP_PUSH , slots [ i ] , 0 ) ;
2019-02-20 01:51:34 +00:00
janetc_emit_s ( c , JOP_PUSH_ARRAY , slots [ i + 1 ] , 0 ) ;
2018-12-05 20:10:04 +00:00
i + = 2 ;
2019-10-01 00:50:42 +00:00
min_arity + + ;
has_splice = 1 ;
2018-12-05 20:10:04 +00:00
} else if ( i + 2 = = count ) {
2019-02-20 01:51:34 +00:00
janetc_emit_ss ( c , JOP_PUSH_2 , slots [ i ] , slots [ i + 1 ] , 0 ) ;
2018-12-05 20:10:04 +00:00
i + = 2 ;
2019-10-01 00:50:42 +00:00
min_arity + = 2 ;
2018-12-05 20:10:04 +00:00
} else if ( slots [ i + 2 ] . flags & JANET_SLOT_SPLICED ) {
2019-02-20 01:51:34 +00:00
janetc_emit_ss ( c , JOP_PUSH_2 , slots [ i ] , slots [ i + 1 ] , 0 ) ;
janetc_emit_s ( c , JOP_PUSH_ARRAY , slots [ i + 2 ] , 0 ) ;
2018-12-05 20:10:04 +00:00
i + = 3 ;
2019-10-01 00:50:42 +00:00
min_arity + = 2 ;
has_splice = 1 ;
2018-12-05 20:10:04 +00:00
} else {
2019-02-20 01:51:34 +00:00
janetc_emit_sss ( c , JOP_PUSH_3 , slots [ i ] , slots [ i + 1 ] , slots [ i + 2 ] , 0 ) ;
2018-12-05 20:10:04 +00:00
i + = 3 ;
2019-10-01 00:50:42 +00:00
min_arity + = 3 ;
2018-12-05 20:10:04 +00:00
}
}
2019-10-01 00:50:42 +00:00
return has_splice ? ( - 1 - min_arity ) : min_arity ;
2018-12-05 20:10:04 +00:00
}
/* Check if a list of slots has any spliced slots */
static int has_spliced ( JanetSlot * slots ) {
int32_t i ;
for ( i = 0 ; i < janet_v_count ( slots ) ; i + + ) {
if ( slots [ i ] . flags & JANET_SLOT_SPLICED )
return 1 ;
}
return 0 ;
2017-12-17 04:11:51 +00:00
}
2018-09-06 02:18:42 +00:00
/* Free slots loaded via janetc_toslots */
void janetc_freeslots ( JanetCompiler * c , JanetSlot * slots ) {
2018-01-05 21:17:55 +00:00
int32_t i ;
2018-09-06 02:18:42 +00:00
for ( i = 0 ; i < janet_v_count ( slots ) ; i + + ) {
janetc_freeslot ( c , slots [ i ] ) ;
2018-01-05 21:17:55 +00:00
}
2018-09-06 02:18:42 +00:00
janet_v_free ( slots ) ;
2018-01-05 21:17:55 +00:00
}
2018-01-04 02:36:10 +00:00
/* Compile some code that will be thrown away. Used to ensure
* that dead code is well formed without including it in the final
* bytecode . */
2018-09-06 02:18:42 +00:00
void janetc_throwaway ( JanetFopts opts , Janet x ) {
JanetCompiler * c = opts . compiler ;
JanetScope unusedScope ;
int32_t bufstart = janet_v_count ( c - > buffer ) ;
int32_t mapbufstart = janet_v_count ( c - > mapbuffer ) ;
janetc_scope ( & unusedScope , c , JANET_SCOPE_UNUSED , " unusued " ) ;
janetc_value ( opts , x ) ;
2021-05-30 15:33:46 +00:00
janetc_lintf ( c , JANET_C_LINT_STRICT , " dead code, consider removing %.2q " , x ) ;
2018-09-06 02:18:42 +00:00
janetc_popscope ( c ) ;
2018-07-01 15:52:15 +00:00
if ( c - > buffer ) {
2018-09-06 02:18:42 +00:00
janet_v__cnt ( c - > buffer ) = bufstart ;
2018-07-01 15:52:15 +00:00
if ( c - > mapbuffer )
2018-09-06 02:18:42 +00:00
janet_v__cnt ( c - > mapbuffer ) = mapbufstart ;
2018-01-05 21:17:55 +00:00
}
2018-01-04 02:36:10 +00:00
}
2018-01-12 15:41:27 +00:00
/* Compile a call or tailcall instruction */
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_call ( JanetFopts opts , JanetSlot * slots , JanetSlot fun ) {
JanetSlot retslot ;
JanetCompiler * c = opts . compiler ;
2018-01-24 22:59:00 +00:00
int specialized = 0 ;
2018-12-05 20:10:04 +00:00
if ( fun . flags & JANET_SLOT_CONSTANT & & ! has_spliced ( slots ) ) {
2018-09-06 02:18:42 +00:00
if ( janet_checktype ( fun . constant , JANET_FUNCTION ) ) {
JanetFunction * f = janet_unwrap_function ( fun . constant ) ;
const JanetFunOptimizer * o = janetc_funopt ( f - > def - > flags ) ;
2018-07-01 23:35:45 +00:00
if ( o & & ( ! o - > can_optimize | | o - > can_optimize ( opts , slots ) ) ) {
2018-01-24 22:59:00 +00:00
specialized = 1 ;
2018-06-29 03:36:31 +00:00
retslot = o - > optimize ( opts , slots ) ;
2018-01-24 22:59:00 +00:00
}
}
2018-09-06 02:18:42 +00:00
/* TODO janet function inlining (no c functions)*/
2018-01-24 22:59:00 +00:00
}
if ( ! specialized ) {
2019-10-01 00:50:42 +00:00
int32_t min_arity = janetc_pushslots ( c , slots ) ;
/* Check for provably incorrect function calls */
if ( fun . flags & JANET_SLOT_CONSTANT ) {
/* Check for bad arity type if fun is a constant */
switch ( janet_type ( fun . constant ) ) {
2019-10-01 00:59:35 +00:00
case JANET_FUNCTION : {
JanetFunction * f = janet_unwrap_function ( fun . constant ) ;
int32_t min = f - > def - > min_arity ;
int32_t max = f - > def - > max_arity ;
if ( min_arity < 0 ) {
/* Call has splices */
min_arity = - 1 - min_arity ;
if ( min_arity > max & & max > = 0 ) {
const uint8_t * es = janet_formatc (
2021-01-04 02:15:51 +00:00
" %v expects at most %d argument%s, got at least %d " ,
fun . constant , max , max = = 1 ? " " : " s " , min_arity ) ;
2019-10-01 00:59:35 +00:00
janetc_error ( c , es ) ;
}
} else {
/* Call has no splices */
if ( min_arity > max & & max > = 0 ) {
const uint8_t * es = janet_formatc (
2021-01-04 02:15:51 +00:00
" %v expects at most %d argument%s, got %d " ,
fun . constant , max , max = = 1 ? " " : " s " , min_arity ) ;
2019-10-01 00:59:35 +00:00
janetc_error ( c , es ) ;
}
if ( min_arity < min ) {
const uint8_t * es = janet_formatc (
2021-01-04 02:15:51 +00:00
" %v expects at least %d argument%s, got %d " ,
fun . constant , min , min = = 1 ? " " : " s " , min_arity ) ;
2019-10-01 00:59:35 +00:00
janetc_error ( c , es ) ;
2019-10-01 00:50:42 +00:00
}
}
2019-10-01 00:59:35 +00:00
}
break ;
2019-10-01 00:50:42 +00:00
case JANET_CFUNCTION :
case JANET_ABSTRACT :
2020-02-22 03:10:42 +00:00
case JANET_NIL :
2019-10-01 00:50:42 +00:00
break ;
case JANET_KEYWORD :
if ( min_arity = = 0 ) {
const uint8_t * es = janet_formatc ( " %v expects at least 1 argument, got 0 " ,
2019-10-01 00:59:35 +00:00
fun . constant ) ;
2019-10-01 00:50:42 +00:00
janetc_error ( c , es ) ;
}
break ;
default :
if ( min_arity > 1 | | min_arity = = 0 ) {
const uint8_t * es = janet_formatc ( " %v expects 1 argument, got %d " ,
2019-10-01 00:59:35 +00:00
fun . constant , min_arity ) ;
2019-10-01 00:50:42 +00:00
janetc_error ( c , es ) ;
}
if ( min_arity < - 2 ) {
const uint8_t * es = janet_formatc ( " %v expects 1 argument, got at least %d " ,
2019-10-01 00:59:35 +00:00
fun . constant , - 1 - min_arity ) ;
2019-10-01 00:50:42 +00:00
janetc_error ( c , es ) ;
}
break ;
}
}
2019-01-15 01:41:32 +00:00
if ( ( opts . flags & JANET_FOPTS_TAIL ) & &
/* Prevent top level tail calls for better errors */
! ( c - > scope - > flags & JANET_SCOPE_TOP ) ) {
2018-09-06 02:18:42 +00:00
janetc_emit_s ( c , JOP_TAILCALL , fun , 0 ) ;
retslot = janetc_cslot ( janet_wrap_nil ( ) ) ;
retslot . flags = JANET_SLOT_RETURNED ;
2018-01-24 22:59:00 +00:00
} else {
2018-09-06 02:18:42 +00:00
retslot = janetc_gettarget ( opts ) ;
janetc_emit_ss ( c , JOP_CALL , retslot , fun , 1 ) ;
2018-01-24 22:59:00 +00:00
}
2018-01-04 02:36:10 +00:00
}
2018-09-06 02:18:42 +00:00
janetc_freeslots ( c , slots ) ;
2018-01-12 15:41:27 +00:00
return retslot ;
}
2018-01-04 02:36:10 +00:00
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_maker ( JanetFopts opts , JanetSlot * slots , int op ) {
JanetCompiler * c = opts . compiler ;
JanetSlot retslot ;
2021-03-17 01:50:17 +00:00
/* Check if this structure is composed entirely of constants */
int can_inline = 1 ;
for ( int32_t i = 0 ; i < janet_v_count ( slots ) ; i + + ) {
if ( ! ( slots [ i ] . flags & JANET_SLOT_CONSTANT ) | |
( slots [ i ] . flags & JANET_SLOT_SPLICED ) ) {
can_inline = 0 ;
break ;
}
}
if ( can_inline & & ( op = = JOP_MAKE_STRUCT ) ) {
JanetKV * st = janet_struct_begin ( janet_v_count ( slots ) / 2 ) ;
for ( int32_t i = 0 ; i < janet_v_count ( slots ) ; i + = 2 ) {
Janet k = slots [ i ] . constant ;
Janet v = slots [ i + 1 ] . constant ;
janet_struct_put ( st , k , v ) ;
}
retslot = janetc_cslot ( janet_wrap_struct ( janet_struct_end ( st ) ) ) ;
janetc_freeslots ( c , slots ) ;
} else if ( can_inline & & ( op = = JOP_MAKE_TUPLE ) ) {
Janet * tup = janet_tuple_begin ( janet_v_count ( slots ) ) ;
for ( int32_t i = 0 ; i < janet_v_count ( slots ) ; i + + ) {
tup [ i ] = slots [ i ] . constant ;
}
retslot = janetc_cslot ( janet_wrap_tuple ( janet_tuple_end ( tup ) ) ) ;
janetc_freeslots ( c , slots ) ;
} else {
janetc_pushslots ( c , slots ) ;
janetc_freeslots ( c , slots ) ;
retslot = janetc_gettarget ( opts ) ;
janetc_emit_s ( c , op , retslot , 1 ) ;
}
2018-07-04 03:07:35 +00:00
return retslot ;
}
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_array ( JanetFopts opts , Janet x ) {
JanetCompiler * c = opts . compiler ;
JanetArray * a = janet_unwrap_array ( x ) ;
return janetc_maker ( opts ,
2019-02-20 01:51:34 +00:00
janetc_toslots ( c , a - > data , a - > count ) ,
JOP_MAKE_ARRAY ) ;
2017-12-30 21:46:59 +00:00
}
2019-02-08 20:49:28 +00:00
static JanetSlot janetc_tuple ( JanetFopts opts , Janet x ) {
JanetCompiler * c = opts . compiler ;
const Janet * t = janet_unwrap_tuple ( x ) ;
return janetc_maker ( opts ,
2019-02-20 01:51:34 +00:00
janetc_toslots ( c , t , janet_tuple_length ( t ) ) ,
JOP_MAKE_TUPLE ) ;
2019-02-08 20:49:28 +00:00
}
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_tablector ( JanetFopts opts , Janet x , int op ) {
JanetCompiler * c = opts . compiler ;
2018-11-16 21:24:10 +00:00
return janetc_maker ( opts ,
2019-02-20 01:51:34 +00:00
janetc_toslotskv ( c , x ) ,
op ) ;
2018-01-12 15:41:27 +00:00
}
2018-01-04 02:36:10 +00:00
2018-09-06 02:18:42 +00:00
static JanetSlot janetc_bufferctor ( JanetFopts opts , Janet x ) {
JanetCompiler * c = opts . compiler ;
JanetBuffer * b = janet_unwrap_buffer ( x ) ;
Janet onearg = janet_stringv ( b - > data , b - > count ) ;
return janetc_maker ( opts ,
2019-02-20 01:51:34 +00:00
janetc_toslots ( c , & onearg , 1 ) ,
JOP_MAKE_BUFFER ) ;
2018-02-03 23:12:07 +00:00
}
2018-07-04 03:07:35 +00:00
/* Expand a macro one time. Also get the special form compiler if we
* find that instead . */
static int macroexpand1 (
2019-02-20 01:51:34 +00:00
JanetCompiler * c ,
Janet x ,
Janet * out ,
const JanetSpecial * * spec ) {
2018-09-06 02:18:42 +00:00
if ( ! janet_checktype ( x , JANET_TUPLE ) )
2018-07-04 03:07:35 +00:00
return 0 ;
2018-09-06 02:18:42 +00:00
const Janet * form = janet_unwrap_tuple ( x ) ;
if ( janet_tuple_length ( form ) = = 0 )
2018-07-04 03:07:35 +00:00
return 0 ;
/* Source map - only set when we get a tuple */
2019-09-22 22:18:28 +00:00
if ( janet_tuple_sm_line ( form ) > = 0 ) {
c - > current_mapping . line = janet_tuple_sm_line ( form ) ;
c - > current_mapping . column = janet_tuple_sm_column ( form ) ;
2018-07-04 03:07:35 +00:00
}
2019-02-22 15:10:41 +00:00
/* Bracketed tuples are not specials or macros! */
if ( janet_tuple_flag ( form ) & JANET_TUPLE_FLAG_BRACKETCTOR )
return 0 ;
2018-09-06 02:18:42 +00:00
if ( ! janet_checktype ( form [ 0 ] , JANET_SYMBOL ) )
2018-07-04 03:07:35 +00:00
return 0 ;
2018-09-06 02:18:42 +00:00
const uint8_t * name = janet_unwrap_symbol ( form [ 0 ] ) ;
const JanetSpecial * s = janetc_special ( name ) ;
2018-07-04 03:07:35 +00:00
if ( s ) {
* spec = s ;
return 0 ;
}
2018-09-06 02:18:42 +00:00
Janet macroval ;
JanetBindingType btype = janet_resolve ( c - > env , name , & macroval ) ;
2022-01-14 08:15:42 +00:00
if ( ! ( btype = = JANET_BINDING_MACRO | | btype = = JANET_BINDING_DYNAMIC_MACRO ) | |
2018-09-06 02:18:42 +00:00
! janet_checktype ( macroval , JANET_FUNCTION ) )
2018-07-04 03:07:35 +00:00
return 0 ;
/* Evaluate macro */
2018-09-06 02:18:42 +00:00
JanetFunction * macro = janet_unwrap_function ( macroval ) ;
2019-12-05 00:36:37 +00:00
int32_t arity = janet_tuple_length ( form ) - 1 ;
JanetFiber * fiberp = janet_fiber ( macro , 64 , arity , form + 1 ) ;
if ( NULL = = fiberp ) {
int32_t minar = macro - > def - > min_arity ;
int32_t maxar = macro - > def - > max_arity ;
const uint8_t * es = NULL ;
if ( minar > = 0 & & arity < minar )
es = janet_formatc ( " macro arity mismatch, expected at least %d, got %d " , minar , arity ) ;
if ( maxar > = 0 & & arity > maxar )
es = janet_formatc ( " macro arity mismatch, expected at most %d, got %d " , maxar , arity ) ;
c - > result . macrofiber = NULL ;
janetc_error ( c , es ) ;
2019-12-31 16:33:03 +00:00
return 0 ;
2019-12-05 00:36:37 +00:00
}
/* Set env */
fiberp - > env = c - > env ;
2018-09-06 02:18:42 +00:00
int lock = janet_gclock ( ) ;
2020-05-18 23:22:43 +00:00
Janet mf_kw = janet_ckeywordv ( " macro-form " ) ;
janet_table_put ( c - > env , mf_kw , x ) ;
2019-12-31 16:33:03 +00:00
Janet tempOut ;
JanetSignal status = janet_continue ( fiberp , janet_wrap_nil ( ) , & tempOut ) ;
2020-05-18 23:22:43 +00:00
janet_table_put ( c - > env , mf_kw , janet_wrap_nil ( ) ) ;
2021-05-28 20:15:34 +00:00
if ( c - > lints ) {
janet_table_put ( c - > env , janet_ckeywordv ( " macro-lints " ) , janet_wrap_array ( c - > lints ) ) ;
}
2018-09-06 02:18:42 +00:00
janet_gcunlock ( lock ) ;
if ( status ! = JANET_SIGNAL_OK ) {
2019-12-31 16:33:03 +00:00
const uint8_t * es = janet_formatc ( " (macro) %V " , tempOut ) ;
2018-07-04 03:07:35 +00:00
c - > result . macrofiber = fiberp ;
2018-09-06 02:18:42 +00:00
janetc_error ( c , es ) ;
2019-12-31 16:33:03 +00:00
return 0 ;
2018-07-04 03:07:35 +00:00
} else {
2019-12-31 16:33:03 +00:00
* out = tempOut ;
2018-07-04 03:07:35 +00:00
}
return 1 ;
}
2018-01-12 15:41:27 +00:00
/* Compile a single value */
2018-09-06 02:18:42 +00:00
JanetSlot janetc_value ( JanetFopts opts , Janet x ) {
JanetSlot ret ;
JanetCompiler * c = opts . compiler ;
JanetSourceMapping last_mapping = c - > current_mapping ;
2018-07-04 03:07:35 +00:00
c - > recursion_guard - - ;
/* Guard against previous errors and unbounded recursion */
2018-09-06 02:18:42 +00:00
if ( c - > result . status = = JANET_COMPILE_ERROR ) return janetc_cslot ( janet_wrap_nil ( ) ) ;
2018-07-04 03:07:35 +00:00
if ( c - > recursion_guard < = 0 ) {
2018-09-06 02:18:42 +00:00
janetc_cerror ( c , " recursed too deeply " ) ;
return janetc_cslot ( janet_wrap_nil ( ) ) ;
2018-01-05 21:17:55 +00:00
}
2018-07-04 03:07:35 +00:00
/* Macro expand. Also gets possible special form and
* refines source mapping cursor if possible . */
2018-09-06 02:18:42 +00:00
const JanetSpecial * spec = NULL ;
int macroi = JANET_MAX_MACRO_EXPAND ;
2018-07-04 17:15:52 +00:00
while ( macroi & &
2018-09-06 02:18:42 +00:00
c - > result . status ! = JANET_COMPILE_ERROR & &
2018-07-04 17:15:52 +00:00
macroexpand1 ( c , x , & x , & spec ) )
2018-07-04 03:07:35 +00:00
macroi - - ;
if ( macroi = = 0 ) {
2018-09-06 02:18:42 +00:00
janetc_cerror ( c , " recursed too deeply in macro expansion " ) ;
return janetc_cslot ( janet_wrap_nil ( ) ) ;
2018-01-04 02:36:10 +00:00
}
2018-07-04 03:07:35 +00:00
/* Special forms */
if ( spec ) {
2018-09-06 02:18:42 +00:00
const Janet * tup = janet_unwrap_tuple ( x ) ;
ret = spec - > compile ( opts , janet_tuple_length ( tup ) - 1 , tup + 1 ) ;
2018-07-04 03:07:35 +00:00
} else {
2018-09-06 02:18:42 +00:00
switch ( janet_type ( x ) ) {
2019-02-20 01:51:34 +00:00
case JANET_TUPLE : {
JanetFopts subopts = janetc_fopts_default ( c ) ;
const Janet * tup = janet_unwrap_tuple ( x ) ;
/* Empty tuple is tuple literal */
if ( janet_tuple_length ( tup ) = = 0 ) {
2019-10-20 19:06:28 +00:00
ret = janetc_cslot ( janet_wrap_tuple ( janet_tuple_n ( NULL , 0 ) ) ) ;
2019-02-20 01:51:34 +00:00
} else if ( janet_tuple_flag ( tup ) & JANET_TUPLE_FLAG_BRACKETCTOR ) { /* [] tuples are not function call */
ret = janetc_tuple ( opts , x ) ;
} else {
JanetSlot head = janetc_value ( subopts , tup [ 0 ] ) ;
subopts . flags = JANET_FUNCTION | JANET_CFUNCTION ;
ret = janetc_call ( opts , janetc_toslots ( c , tup + 1 , janet_tuple_length ( tup ) - 1 ) , head ) ;
janetc_freeslot ( c , head ) ;
2018-01-28 20:29:47 +00:00
}
2019-02-20 01:51:34 +00:00
ret . flags & = ~ JANET_SLOT_SPLICED ;
}
break ;
2018-09-06 02:18:42 +00:00
case JANET_SYMBOL :
2019-01-15 01:41:32 +00:00
ret = janetc_resolve ( c , janet_unwrap_symbol ( x ) ) ;
2018-07-04 03:07:35 +00:00
break ;
2018-09-06 02:18:42 +00:00
case JANET_ARRAY :
ret = janetc_array ( opts , x ) ;
2018-07-04 03:07:35 +00:00
break ;
2018-09-06 02:18:42 +00:00
case JANET_STRUCT :
ret = janetc_tablector ( opts , x , JOP_MAKE_STRUCT ) ;
2018-07-04 03:07:35 +00:00
break ;
2018-09-06 02:18:42 +00:00
case JANET_TABLE :
ret = janetc_tablector ( opts , x , JOP_MAKE_TABLE ) ;
2018-07-04 03:07:35 +00:00
break ;
2018-09-06 02:18:42 +00:00
case JANET_BUFFER :
ret = janetc_bufferctor ( opts , x ) ;
2018-07-04 03:07:35 +00:00
break ;
default :
2018-09-06 02:18:42 +00:00
ret = janetc_cslot ( x ) ;
2018-07-04 03:07:35 +00:00
break ;
}
2018-01-04 02:36:10 +00:00
}
2018-07-04 03:07:35 +00:00
2018-09-06 02:18:42 +00:00
if ( c - > result . status = = JANET_COMPILE_ERROR )
return janetc_cslot ( janet_wrap_nil ( ) ) ;
if ( opts . flags & JANET_FOPTS_TAIL )
2019-01-15 01:41:32 +00:00
ret = janetc_return ( c , ret ) ;
2018-09-06 02:18:42 +00:00
if ( opts . flags & JANET_FOPTS_HINT ) {
2019-01-15 01:41:32 +00:00
janetc_copy ( c , opts . hint , ret ) ;
2018-01-16 04:31:39 +00:00
ret = opts . hint ;
}
2018-12-17 17:06:50 +00:00
c - > current_mapping = last_mapping ;
2019-01-15 01:41:32 +00:00
c - > recursion_guard + + ;
2018-01-12 15:41:27 +00:00
return ret ;
2018-01-04 02:36:10 +00:00
}
2020-07-04 00:54:58 +00:00
/* Add function flags to janet functions */
void janet_def_addflags ( JanetFuncDef * def ) {
int32_t set_flags = 0 ;
int32_t unset_flags = 0 ;
/* pos checks */
if ( def - > name ) set_flags | = JANET_FUNCDEF_FLAG_HASNAME ;
if ( def - > source ) set_flags | = JANET_FUNCDEF_FLAG_HASSOURCE ;
if ( def - > defs ) set_flags | = JANET_FUNCDEF_FLAG_HASDEFS ;
if ( def - > environments ) set_flags | = JANET_FUNCDEF_FLAG_HASENVS ;
if ( def - > sourcemap ) set_flags | = JANET_FUNCDEF_FLAG_HASSOURCEMAP ;
if ( def - > closure_bitset ) set_flags | = JANET_FUNCDEF_FLAG_HASCLOBITSET ;
/* negative checks */
if ( ! def - > name ) unset_flags | = JANET_FUNCDEF_FLAG_HASNAME ;
if ( ! def - > source ) unset_flags | = JANET_FUNCDEF_FLAG_HASSOURCE ;
if ( ! def - > defs ) unset_flags | = JANET_FUNCDEF_FLAG_HASDEFS ;
if ( ! def - > environments ) unset_flags | = JANET_FUNCDEF_FLAG_HASENVS ;
if ( ! def - > sourcemap ) unset_flags | = JANET_FUNCDEF_FLAG_HASSOURCEMAP ;
if ( ! def - > closure_bitset ) unset_flags | = JANET_FUNCDEF_FLAG_HASCLOBITSET ;
/* Update flags */
def - > flags | = set_flags ;
def - > flags & = ~ unset_flags ;
}
2018-01-04 02:36:10 +00:00
/* Compile a funcdef */
2020-07-04 01:41:55 +00:00
/* Once the various other settings of the FuncDef have been tweaked,
* call janet_def_addflags to set the proper flags for the funcdef */
2018-09-06 02:18:42 +00:00
JanetFuncDef * janetc_pop_funcdef ( JanetCompiler * c ) {
JanetScope * scope = c - > scope ;
JanetFuncDef * def = janet_funcdef_alloc ( ) ;
2018-07-01 15:52:15 +00:00
def - > slotcount = scope - > ra . max + 1 ;
2018-01-04 02:36:10 +00:00
2018-09-06 02:18:42 +00:00
janet_assert ( scope - > flags & JANET_SCOPE_FUNCTION , " expected function scope " ) ;
2018-01-21 19:39:32 +00:00
2018-01-04 02:36:10 +00:00
/* Copy envs */
2018-09-06 02:18:42 +00:00
def - > environments_length = janet_v_count ( scope - > envs ) ;
def - > environments = janet_v_flatten ( scope - > envs ) ;
2018-01-04 02:36:10 +00:00
2018-09-06 02:18:42 +00:00
def - > constants_length = janet_v_count ( scope - > consts ) ;
def - > constants = janet_v_flatten ( scope - > consts ) ;
2018-01-04 02:36:10 +00:00
2018-09-06 02:18:42 +00:00
def - > defs_length = janet_v_count ( scope - > defs ) ;
def - > defs = janet_v_flatten ( scope - > defs ) ;
2018-01-04 02:36:10 +00:00
2018-06-29 03:36:31 +00:00
/* Copy bytecode (only last chunk) */
2018-09-06 02:18:42 +00:00
def - > bytecode_length = janet_v_count ( c - > buffer ) - scope - > bytecode_start ;
2018-01-04 02:36:10 +00:00
if ( def - > bytecode_length ) {
2020-01-03 04:02:57 +00:00
size_t s = sizeof ( int32_t ) * ( size_t ) def - > bytecode_length ;
2021-03-23 10:00:48 +00:00
def - > bytecode = janet_malloc ( s ) ;
2018-01-04 02:36:10 +00:00
if ( NULL = = def - > bytecode ) {
2018-09-06 02:18:42 +00:00
JANET_OUT_OF_MEMORY ;
2018-01-04 02:36:10 +00:00
}
2020-01-29 05:38:52 +00:00
safe_memcpy ( def - > bytecode , c - > buffer + scope - > bytecode_start , s ) ;
2018-09-06 02:18:42 +00:00
janet_v__cnt ( c - > buffer ) = scope - > bytecode_start ;
2019-06-20 15:52:43 +00:00
if ( NULL ! = c - > mapbuffer & & c - > source ) {
2020-01-03 04:02:57 +00:00
size_t s = sizeof ( JanetSourceMapping ) * ( size_t ) def - > bytecode_length ;
2021-03-23 10:00:48 +00:00
def - > sourcemap = janet_malloc ( s ) ;
2018-01-05 21:17:55 +00:00
if ( NULL = = def - > sourcemap ) {
2018-09-06 02:18:42 +00:00
JANET_OUT_OF_MEMORY ;
2018-01-05 21:17:55 +00:00
}
2020-01-29 05:38:52 +00:00
safe_memcpy ( def - > sourcemap , c - > mapbuffer + scope - > bytecode_start , s ) ;
2018-09-06 02:18:42 +00:00
janet_v__cnt ( c - > mapbuffer ) = scope - > bytecode_start ;
2018-01-04 02:36:10 +00:00
}
}
2018-06-29 03:36:31 +00:00
/* Get source from parser */
2018-06-29 14:37:50 +00:00
def - > source = c - > source ;
2018-06-29 03:36:31 +00:00
2018-01-04 02:36:10 +00:00
def - > arity = 0 ;
2019-03-12 04:23:14 +00:00
def - > min_arity = 0 ;
2018-01-04 02:36:10 +00:00
def - > flags = 0 ;
2018-09-06 02:18:42 +00:00
if ( scope - > flags & JANET_SCOPE_ENV ) {
def - > flags | = JANET_FUNCDEF_FLAG_NEEDSENV ;
2018-01-04 02:36:10 +00:00
}
2018-11-16 21:24:10 +00:00
2020-03-18 14:30:10 +00:00
/* Copy upvalue bitset */
if ( scope - > ua . count ) {
/* Number of u32s we need to create a bitmask for all slots */
2020-05-28 15:47:22 +00:00
int32_t slotchunks = ( def - > slotcount + 31 ) > > 5 ;
/* numchunks is min of slotchunks and scope->ua.count */
int32_t numchunks = slotchunks > scope - > ua . count ? scope - > ua . count : slotchunks ;
2021-03-23 10:00:48 +00:00
uint32_t * chunks = janet_calloc ( sizeof ( uint32_t ) , slotchunks ) ;
2020-03-18 14:30:10 +00:00
if ( NULL = = chunks ) {
JANET_OUT_OF_MEMORY ;
}
2020-05-28 15:47:22 +00:00
memcpy ( chunks , scope - > ua . chunks , sizeof ( uint32_t ) * numchunks ) ;
2020-03-18 14:30:10 +00:00
/* Register allocator preallocates some registers [240-255, high 16 bits of chunk index 7], we can ignore those. */
if ( scope - > ua . count > 7 ) chunks [ 7 ] & = 0xFFFFU ;
def - > closure_bitset = chunks ;
}
2018-01-04 02:36:10 +00:00
/* Pop the scope */
2018-09-06 02:18:42 +00:00
janetc_popscope ( c ) ;
2018-01-04 02:36:10 +00:00
2023-02-01 08:39:24 +00:00
if ( janet_truthy ( janet_dyn ( " debug " ) ) ) {
2023-02-01 10:06:33 +00:00
JanetSymbolSlot * last_symbols = janet_v_last ( c - > local_symbols ) ;
2023-02-01 08:39:24 +00:00
2023-02-01 10:06:33 +00:00
def - > symbolslots_length = janet_v_count ( last_symbols ) ;
2023-02-01 08:39:24 +00:00
2023-02-01 10:06:33 +00:00
def - > symbolslots = janet_malloc ( sizeof ( JanetSymbolSlot ) * def - > symbolslots_length ) ;
if ( NULL = = def - > bytecode ) {
JANET_OUT_OF_MEMORY ;
}
// add in reverse, because scopes have been added filo
for ( int i = 0 ; i < janet_v_count ( last_symbols ) ; i + + ) {
def - > symbolslots [ def - > symbolslots_length - i - 1 ] = last_symbols [ i ] ;
2023-02-01 08:39:24 +00:00
}
}
2023-02-01 10:06:33 +00:00
janet_v_pop ( c - > local_symbols ) ;
2023-02-01 08:39:24 +00:00
2018-01-04 02:36:10 +00:00
return def ;
}
2017-12-21 04:03:34 +00:00
/* Initialize a compiler */
2021-05-28 20:12:05 +00:00
static void janetc_init ( JanetCompiler * c , JanetTable * env , const uint8_t * where , JanetArray * lints ) {
2018-07-01 15:52:15 +00:00
c - > scope = NULL ;
2017-12-21 04:03:34 +00:00
c - > buffer = NULL ;
c - > mapbuffer = NULL ;
2018-09-06 02:18:42 +00:00
c - > recursion_guard = JANET_RECURSION_GUARD ;
2017-12-30 21:46:59 +00:00
c - > env = env ;
2023-02-01 10:06:33 +00:00
c - > local_symbols = NULL ;
2018-06-29 14:37:50 +00:00
c - > source = where ;
2019-09-22 22:18:28 +00:00
c - > current_mapping . line = - 1 ;
c - > current_mapping . column = - 1 ;
2021-05-28 20:12:05 +00:00
c - > lints = lints ;
2018-01-05 21:17:55 +00:00
/* Init result */
c - > result . error = NULL ;
2018-09-06 02:18:42 +00:00
c - > result . status = JANET_COMPILE_OK ;
2018-06-29 05:15:47 +00:00
c - > result . funcdef = NULL ;
2018-07-04 03:07:35 +00:00
c - > result . macrofiber = NULL ;
2019-09-22 22:18:28 +00:00
c - > result . error_mapping . line = - 1 ;
c - > result . error_mapping . column = - 1 ;
2017-12-21 04:03:34 +00:00
}
2017-12-17 04:11:51 +00:00
/* Deinitialize a compiler struct */
2018-09-06 02:18:42 +00:00
static void janetc_deinit ( JanetCompiler * c ) {
janet_v_free ( c - > buffer ) ;
janet_v_free ( c - > mapbuffer ) ;
2023-02-01 10:06:33 +00:00
janet_v_free ( c - > local_symbols ) ;
2023-02-01 20:12:42 +00:00
c - > env = NULL ;
2017-12-16 06:17:53 +00:00
}
2018-01-05 21:17:55 +00:00
/* Compile a form. */
2021-05-28 20:12:05 +00:00
JanetCompileResult janet_compile_lint ( Janet source ,
JanetTable * env , const uint8_t * where , JanetArray * lints ) {
2018-09-06 02:18:42 +00:00
JanetCompiler c ;
JanetScope rootscope ;
JanetFopts fopts ;
2017-12-16 06:17:53 +00:00
2021-05-28 20:12:05 +00:00
janetc_init ( & c , env , where , lints ) ;
2017-12-16 06:17:53 +00:00
2017-12-17 04:11:51 +00:00
/* Push a function scope */
2023-02-01 10:45:13 +00:00
janet_v_push ( c . local_symbols , NULL ) ;
2018-09-06 02:18:42 +00:00
janetc_scope ( & rootscope , & c , JANET_SCOPE_FUNCTION | JANET_SCOPE_TOP , " root " ) ;
2017-12-21 04:03:34 +00:00
2018-01-05 21:17:55 +00:00
/* Set initial form options */
fopts . compiler = & c ;
2018-09-06 02:18:42 +00:00
fopts . flags = JANET_FOPTS_TAIL | JANET_SLOTTYPE_ANY ;
fopts . hint = janetc_cslot ( janet_wrap_nil ( ) ) ;
2017-12-17 04:11:51 +00:00
/* Compile the value */
2018-09-06 02:18:42 +00:00
janetc_value ( fopts , source ) ;
2017-12-21 04:03:34 +00:00
2018-09-06 02:18:42 +00:00
if ( c . result . status = = JANET_COMPILE_OK ) {
JanetFuncDef * def = janetc_pop_funcdef ( & c ) ;
def - > name = janet_cstring ( " _thunk " ) ;
2020-07-04 01:41:55 +00:00
janet_def_addflags ( def ) ;
2018-01-20 22:19:47 +00:00
c . result . funcdef = def ;
2018-06-29 05:15:47 +00:00
} else {
2018-06-29 14:37:50 +00:00
c . result . error_mapping = c . current_mapping ;
2018-09-06 02:18:42 +00:00
janetc_popscope ( & c ) ;
2023-02-01 08:39:24 +00:00
if ( janet_truthy ( janet_dyn ( " debug " ) ) ) {
2023-02-01 10:06:33 +00:00
janet_v_pop ( c . local_symbols ) ;
2023-02-01 08:39:24 +00:00
}
2018-01-05 21:17:55 +00:00
}
2017-12-17 04:11:51 +00:00
2018-09-06 02:18:42 +00:00
janetc_deinit ( & c ) ;
2017-12-17 04:11:51 +00:00
2018-01-05 21:17:55 +00:00
return c . result ;
2017-12-17 04:11:51 +00:00
}
2021-05-28 20:12:05 +00:00
JanetCompileResult janet_compile ( Janet source , JanetTable * env , const uint8_t * where ) {
return janet_compile_lint ( source , env , where , NULL ) ;
}
2018-01-16 04:31:39 +00:00
/* C Function for compiling */
2022-08-18 19:33:59 +00:00
JANET_CORE_FN ( cfun_compile ,
2021-07-26 00:07:53 +00:00
" (compile ast &opt env source lints) " ,
" Compiles an Abstract Syntax Tree (ast) into a function. "
" Pair the compile function with parsing functionality to implement "
" eval. Returns a new function and does not modify ast. Returns an error "
" struct with keys :line, :column, and :error if compilation fails. "
" If a `lints` array is given, linting messages will be appended to the array. "
" Each message will be a tuple of the form `(level line col message)`. " ) {
2021-05-28 20:12:05 +00:00
janet_arity ( argc , 1 , 4 ) ;
2022-11-11 17:25:06 +00:00
JanetTable * env = ( argc > 1 & & ! janet_checktype ( argv [ 1 ] , JANET_NIL ) )
2022-11-27 16:15:01 +00:00
? janet_gettable ( argv , 1 ) : janet_vm . fiber - > env ;
2019-05-20 15:34:07 +00:00
if ( NULL = = env ) {
env = janet_table ( 0 ) ;
2021-07-17 01:59:03 +00:00
janet_vm . fiber - > env = env ;
2019-05-20 15:34:07 +00:00
}
2018-06-29 14:37:50 +00:00
const uint8_t * source = NULL ;
2021-05-28 20:12:05 +00:00
if ( argc > = 3 ) {
2021-12-15 03:17:35 +00:00
Janet x = argv [ 2 ] ;
if ( janet_checktype ( x , JANET_STRING ) ) {
source = janet_unwrap_string ( x ) ;
} else if ( janet_checktype ( x , JANET_KEYWORD ) ) {
source = janet_unwrap_keyword ( x ) ;
2022-11-11 17:25:06 +00:00
} else if ( ! janet_checktype ( x , JANET_NIL ) ) {
2021-12-15 03:17:35 +00:00
janet_panic_type ( x , 2 , JANET_TFLAG_STRING | JANET_TFLAG_KEYWORD ) ;
}
2018-06-29 03:36:31 +00:00
}
2022-11-11 17:25:06 +00:00
JanetArray * lints = ( argc > = 4 & & ! janet_checktype ( argv [ 3 ] , JANET_NIL ) )
2022-11-27 16:15:01 +00:00
? janet_getarray ( argv , 3 ) : NULL ;
2021-05-28 20:12:05 +00:00
JanetCompileResult res = janet_compile_lint ( argv [ 0 ] , env , source , lints ) ;
2018-09-06 02:18:42 +00:00
if ( res . status = = JANET_COMPILE_OK ) {
2019-01-06 01:09:03 +00:00
return janet_wrap_function ( janet_thunk ( res . funcdef ) ) ;
2018-01-16 04:31:39 +00:00
} else {
2019-01-06 01:09:03 +00:00
JanetTable * t = janet_table ( 4 ) ;
2019-01-03 00:41:07 +00:00
janet_table_put ( t , janet_ckeywordv ( " error " ) , janet_wrap_string ( res . error ) ) ;
2021-01-30 17:33:15 +00:00
if ( res . error_mapping . line > 0 ) {
janet_table_put ( t , janet_ckeywordv ( " line " ) , janet_wrap_integer ( res . error_mapping . line ) ) ;
}
if ( res . error_mapping . column > 0 ) {
janet_table_put ( t , janet_ckeywordv ( " column " ) , janet_wrap_integer ( res . error_mapping . column ) ) ;
}
2018-07-04 03:07:35 +00:00
if ( res . macrofiber ) {
2019-01-03 00:41:07 +00:00
janet_table_put ( t , janet_ckeywordv ( " fiber " ) , janet_wrap_fiber ( res . macrofiber ) ) ;
2018-07-04 03:07:35 +00:00
}
2019-01-06 01:09:03 +00:00
return janet_wrap_table ( t ) ;
2018-01-16 04:31:39 +00:00
}
}
2018-01-27 20:15:09 +00:00
2019-01-06 01:09:03 +00:00
void janet_lib_compile ( JanetTable * env ) {
2021-07-26 00:07:53 +00:00
JanetRegExt cfuns [ ] = {
2022-08-18 19:33:59 +00:00
JANET_CORE_REG ( " compile " , cfun_compile ) ,
2021-07-26 22:54:26 +00:00
JANET_REG_END
2021-07-26 00:07:53 +00:00
} ;
janet_core_cfuns_ext ( env , NULL , cfuns ) ;
2018-01-27 20:15:09 +00:00
}