vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

prolog.lua

(20396B)


      1 -- Copyright 2006-2025 Mitchell. See LICENSE.
      2 -- Lexer enhanced to conform to the realities of Prologs on the ground by
      3 -- Michael T. Richter.  Copyright is explicitly assigned back to Mitchell.
      4 -- Prolog LPeg lexer.
      5 
      6 --[[
      7   Prologs are notoriously fractious with many barely-compatible dialects.  To
      8   make Textadept more useful for these cases, directives and keywords are
      9   grouped by dialect.  Selecting a dialect is a simple matter of setting the
     10   buffer/lexer property "prolog.dialect" in init.lua.  Dialects currently in
     11   the lexer file are:
     12     - 'iso': the generic ISO standard without modules.
     13     - 'gprolog': GNU Prolog.
     14     - 'swipl': SWI-Prolog.
     15 
     16   The default dialect is 'iso' if none is defined.  (You probably don't want
     17   this.)
     18 
     19   Note that there will be undoubtedly duplicated entries in various categories
     20   because of the flexibility of Prolog and the automated tools used to gather
     21   most information.  This is not an issue, however, because directives override
     22   arity-0 predicates which override arity-1+ predicates which override bifs
     23   which override operators.
     24 ]]
     25 
     26 local lexer = require('lexer')
     27 
     28 local token, word_match = lexer.token, lexer.word_match
     29 local P, S = lpeg.P, lpeg.S
     30 
     31 local lex = lexer.new('prolog')
     32 
     33 local dialect = lexer.property['prolog.dialect']
     34 if dialect ~= 'gprolog' and dialog ~= 'swipl' then dialect = 'iso' end
     35 
     36 -- Directives.
     37 local directives = {}
     38 directives.iso = [[
     39   -- Gathered by inspection of GNU Prolog documentation.
     40   dynamic multifile discontiguous include ensure_loaded op char_conversion
     41   set_prolog_flag initialization
     42 ]]
     43 directives.gprolog = directives.iso .. [[
     44   -- Gathered by inspection of GNU Prolog documentation.
     45   public ensure_linked built_in if else endif elif foreign
     46 ]]
     47 directives.swipl = directives.iso .. [[
     48   -- Gathered by liberal use of grep on the SWI source and libraries.
     49   coinductive current_predicate_option expects_dialect http_handler listen
     50   module multifile use_foreign_library use_module dynamic http_handler
     51   initialization json_object multifile record use_module abolish
     52   arithmetic_function asserta at_halt begin_tests chr_constraint chr_option
     53   chr_type clear_cache constraints consult create_prolog_flag
     54   current_prolog_flag debug discontiguous dynamic elif else encoding end_tests
     55   endif expects_dialect export forall format format_predicate html_meta
     56   html_resource http_handler http_request_expansion if include
     57   init_color_term_flag init_options initialization json_object
     58   lazy_list_iterator license listen load_extensions load_files
     59   load_foreign_library meta_predicate mode module module_transparent multifile
     60   noprofile op pce_begin_class pce_end_class pce_global pce_group persistent
     61   pop_operators pred predicate_options print_message prolog_load_context prompt
     62   public push_hprolog_library push_ifprolog_library, push_operators
     63   push_sicstus_library push_xsb_library push_yap_library, quasi_quotation_syntax
     64   record redefine_system_predicate reexport register_iri_scheme residual_goals
     65   retract set_module set_prolog_flag set_script_dir set_test_options setenv
     66   setting style_check table thread_local thread_local	message type
     67   use_class_template use_foreign_library use_module utter volatile build_schema
     68   chr_constraint chr_option chr_type cql_option determinate discontiguous
     69   dynamic endif format_predicate if initialization license meta_predicate mode
     70   module multifile op reexport thread_local use_module volatile
     71 ]]
     72 lex:add_rule('directive',
     73 	token(lexer.WHITESPACE, lexer.starts_line(S(' \t'))^0) * token(lexer.OPERATOR, ':-') *
     74 		token(lexer.WHITESPACE, S(' \t')^0) * token(lexer.PREPROCESSOR, word_match(directives[dialect])))
     75 
     76 -- Whitespace.
     77 lex:add_rule('whitespace', token(lexer.WHITESPACE, lexer.space^1))
     78 
     79 -- Keywords.
     80 local zero_arity_keywords = {}
     81 zero_arity_keywords.iso = [[
     82   -- eyeballed from GNU Prolog documentation
     83   true fail pi float_overflow int_overflow int_underflow undefined asserta
     84   assertz retract retractall clause abolish current_predicate findall bagof
     85   setof at_end_of_stream flush_output nl halt false
     86 ]]
     87 zero_arity_keywords.gprolog = [[
     88   -- Collected automatically via current_predicate/1 with some cleanup.
     89   at_end_of_stream wam_debug listing flush_output fail told false top_level
     90   shell trace debugging seen repeat abort nl statistics halt notrace randomize
     91   true nospyall nodebug debug stop break
     92 ]]
     93 zero_arity_keywords.swipl = [[
     94   -- Collected automatically via current_predicate/1 with some cleanup.
     95   noprotocol compiling ttyflush true abort license known_licenses
     96   print_toplevel_variables initialize mutex_statistics break reset_profiler
     97   win_has_menu version prolog abolish_nonincremental_tables false halt undefined
     98   abolish_all_tables reload_library_index garbage_collect repeat nospyall
     99   tracing trace notrace trim_stacks garbage_collect_clauses
    100   garbage_collect_atoms mutex_unlock_all seen told nl debugging fail
    101   at_end_of_stream attach_packs flush_output true
    102 ]]
    103 local one_plus_arity_keywords = {}
    104 one_plus_arity_keywords.iso = [[
    105   -- eyeballed from GNU Prolog documentation
    106   call catch throw var nonvar atom integer float number atomic compound
    107   callable ground unify_with_occurs_check compare functor arg copy_term
    108   term_variables subsumes_term acyclic_term predicate_property current_input
    109   current_output set_input set_output open close current_stream stream_property
    110   set_stream_position get_char get_code is peek_char peek_code put_char putcode
    111   get_byte peek_byte read_term read write_term write writeq write_canonical
    112   char_conversion current_char_conversion call once repeat atom_length
    113   atom_concat sub_atom char_code atom_chars atom_codes
    114 ]]
    115 one_plus_arity_keywords.gprolog = [[
    116   -- Collected automatically via current_predicate/1 with some cleanup.
    117   abolish absolute_file_name acyclic_term add_linedit_completion
    118   add_stream_alias add_stream_mirror append architecture arg argument_counter
    119   argument_list argument_value asserta assertz at_end_of_stream atom atom_chars
    120   atom_codes atom_concat atom_length atom_property atomic bagof between
    121   bind_variables call call_det call_with_args callable catch change_directory
    122   char_code char_conversion character_count clause close close_input_atom_stream
    123   close_input_chars_stream close_input_codes_stream close_output_atom_stream
    124   close_output_chars_stream close_output_codes_stream compare compound consult
    125   copy_term cpu_time create_pipe current_alias current_atom current_bip_name
    126   current_char_conversion current_input current_mirror current_op current_output
    127   current_predicate current_prolog_flag current_stream date_time
    128   decompose_file_name delete delete_directory delete_file directory_files
    129   display display_to_atom display_to_chars display_to_codes environ exec
    130   expand_term fd_all_different fd_at_least_one fd_at_most_one fd_atleast
    131   fd_atmost fd_cardinality fd_dom fd_domain fd_domain_bool fd_element
    132   fd_element_var fd_exactly fd_has_extra_cstr fd_has_vector fd_labeling
    133   fd_labelingff fd_max fd_max_integer fd_maximize fd_min fd_minimize
    134   fd_not_prime fd_only_one fd_prime fd_reified_in fd_relation fd_relationc
    135   fd_set_vector_max fd_size fd_use_vector fd_var fd_vector_max file_exists
    136   file_permission file_property find_linedit_completion findall flatten float
    137   flush_output for forall fork_prolog format format_to_atom format_to_chars
    138   format_to_codes functor g_array_size g_assign g_assignb g_dec g_deco g_inc
    139   g_inco g_link g_read g_reset_bit g_set_bit g_test_reset_bit g_test_set_bit
    140   generic_var get get_byte get_char get_code get_key get_key_no_echo
    141   get_linedit_prompt get_print_stream get_seed get0 ground halt host_name
    142   hostname_address integer is_absolute_file_name is_list is_relative_file_name
    143   keysort last last_read_start_line_column leash length line_count line_position
    144   list list_or_partial_list listing load lower_upper make_directory maplist
    145   max_list member memberchk min_list msort name name_query_vars
    146   name_singleton_vars new_atom nl non_fd_var non_generic_var nonvar nospy nth
    147   nth0 nth1 number number_atom number_chars number_codes numbervars once op open
    148   open_input_atom_stream open_input_chars_stream open_input_codes_stream
    149   open_output_atom_stream open_output_chars_stream open_output_codes_stream
    150   os_version partial_list peek_byte peek_char peek_code permutation phrase popen
    151   portray_clause predicate_property prefix print print_to_atom print_to_chars
    152   print_to_codes prolog_file_name prolog_pid put put_byte put_char put_code
    153   random read read_atom read_from_atom read_from_chars read_from_codes
    154   read_integer read_number read_pl_state_file read_term read_term_from_atom
    155   read_term_from_chars read_term_from_codes read_token read_token_from_atom
    156   read_token_from_chars read_token_from_codes real_time remove_stream_mirror
    157   rename_file retract retractall reverse see seeing seek select send_signal
    158   set_bip_name set_input set_linedit_prompt set_output set_prolog_flag set_seed
    159   set_stream_buffering set_stream_eof_action set_stream_line_column
    160   set_stream_position set_stream_type setarg setof shell skip sleep socket
    161   socket_accept socket_bind socket_close socket_connect socket_listen sort spawn
    162   spy spypoint_condition sr_change_options sr_close sr_current_descriptor
    163   sr_error_from_exception sr_get_error_counters sr_get_file_name
    164   sr_get_include_list sr_get_include_stream_list sr_get_module sr_get_position
    165   sr_get_size_counters sr_get_stream sr_new_pass sr_open sr_read_term
    166   sr_set_error_counters sr_write_error sr_write_message statistics
    167   stream_line_column stream_position stream_property sub_atom sublist
    168   subsumes_term subtract succ suffix sum_list syntax_error_info system
    169   system_time tab tell telling temporary_file temporary_name term_hash term_ref
    170   term_variables throw unget_byte unget_char unget_code unify_with_occurs_check
    171   unlink user_time var wait working_directory write write_canonical
    172   write_canonical_to_atom write_canonical_to_chars write_canonical_to_codes
    173   write_pl_state_file write_term write_term_to_atom write_term_to_chars
    174   write_term_to_codes write_to_atom write_to_chars write_to_codes writeq
    175   writeq_to_atom writeq_to_chars writeq_to_codes
    176 ]]
    177 one_plus_arity_keywords.swipl = [[
    178   -- Collected automatically via current_predicate/1 with some cleanup.
    179   prolog_exception_hook term_expansion expand_answer message_property resource
    180   help goal_expansion file_search_path prolog_clause_name thread_message_hook
    181   prolog_file_type goal_expansion prolog_predicate_name exception writeln
    182   term_expansion expand_query url_path message_hook library_directory resource
    183   portray prolog_load_file prolog_list_goal ansi_format source_file_property
    184   asserta call_dcg source_location wait_for_input locale_destroy set_locale
    185   read_pending_codes thread_join open_dde_conversation win_folder protocol
    186   copy_stream_data current_locale read_pending_chars win_add_dll_directory
    187   protocola thread_property win_shell goal_expansion phrase gc_file_search_cache
    188   dcg_translate_rule protocolling win_registry_get_value term_expansion
    189   dcg_translate_rule assert copy_stream_data once bagof prompt1 tnot assertz
    190   phrase sort ignore thread_statistics assert locale_create
    191   win_remove_dll_directory term_expansion read_term asserta clause assertz
    192   predicate_option_type is_thread get_single_char set_prolog_IO expand_goal
    193   ground message_queue_create locale_property close_dde_conversation
    194   goal_expansion clause zipper_open_new_file_in_zip term_to_atom with_output_to
    195   module expand_term redefine_system_predicate thread_detach dde_execute
    196   term_string read_clause compile_predicates predicate_option_mode noprofile
    197   read_term_from_atom cancel_halt non_terminal atom_to_term line_position frozen
    198   dde_request findnsols prolog_skip_level prolog_current_choice get get_attrs
    199   license var_property nb_delete unwrap_predicate zipper_open_current put_attrs
    200   dde_poke set_stream read_term zip_file_info_ memberchk seek expand_goal get0
    201   call var integer attach_packs byte_count zipper_goto findnsols character_count
    202   expand_term get_flag atom line_count set_flag atomic tab create_prolog_flag
    203   copy_term import_module verbose_expansion b_setval duplicate_term
    204   prolog_load_context attach_packs prolog_listen b_getval prolog_frame_attribute
    205   prompt copy_term_nat nb_linkval tab prolog_choice_attribute set_prolog_flag
    206   nb_getval prolog_skip_frame del_attrs skip sort license open_null_stream
    207   nb_current prolog_listen msort is_list is_stream get keysort win_shell
    208   prolog_unlisten notrace get0 add_import_module wildcard_match profiler
    209   delete_directory trie_gen_compiled expand_file_name file_name_extension
    210   delete_file writeq win_module_file call write get_dict win_exec
    211   directory_files trie_insert make_directory engine_next_reified del_dict sleep
    212   getenv call_continuation trie_gen_compiled prolog_to_os_filename
    213   is_absolute_file_name trie_insert engine_fetch engine_create strip_module call
    214   delete_import_module write_canonical compile_aux_clauses setenv callable
    215   is_engine write_term call set_module call halt catch findall trie_gen
    216   trie_destroy rename_file shift unify_with_occurs_check engine_yield forall
    217   unsetenv trie_term file_directory_name version current_engine file_base_name
    218   engine_self import trie_gen trie_lookup write_term trie_update freeze
    219   engine_post export put_dict same_file trie_new call trie_delete start_tabling
    220   is_trie residual_goals thread_peek_message thread_get_message dict_pairs
    221   set_end_of_stream call_cleanup current_predicate arg dict_create
    222   thread_setconcurrency read_link is_dict at_halt tmp_file not put_dict
    223   setup_call_cleanup abolish_nonincremental_tables time_file
    224   start_subsumptive_tabling char_conversion compound sub_atom access_file call
    225   call_cleanup abolish nonvar current_functor abolish_module_tables
    226   subsumes_term engine_post call retractall compare engine_next prolog_cut_to
    227   size_file current_char_conversion predicate_property nonground engine_destroy
    228   message_queue_property format abolish qcompile thread_send_message stream_pair
    229   message_queue_create same_term number select_dict catch_with_backtrace
    230   thread_get_message thread_send_message win_insert_menu_item message_queue_set
    231   <meta-call> exists_directory copy_term nb_set_dict prolog_nodebug functor
    232   current_table cyclic_term untable read exists_file thread_peek_message
    233   b_set_dict engine_create prolog_debug acyclic_term writeln get_dict
    234   compound_name_arity abolish_table_subgoals start_tabling trie_insert
    235   nb_link_dict message_queue_destroy thread_get_message is_dict nth_clause
    236   absolute_file_name term_singletons make_library_index set_output retract
    237   context_module current_trie term_attvars load_files get_char ensure_loaded
    238   current_input prolog_current_frame make_library_index term_variables
    239   compound_name_arguments reexport autoload_path get_code set_input flag
    240   thread_create use_module findall thread_join call_with_inference_limit
    241   var_number dwim_match consult peek_code close nospy print_message
    242   term_variables trie_property read_history get_byte default_module get_byte
    243   print on_signal get_char call_residue_vars dwim_match atom_prefix unifiable
    244   use_module numbervars load_files get_code open format_time
    245   copy_predicate_clauses reexport leash current_output sub_string close
    246   format_time atom_codes stamp_date_time require name open_shared_object open
    247   atom_chars current_predicate format tmp_file_stream term_hash rational
    248   source_file reset atom_concat atom_length current_prolog_flag rational
    249   dwim_predicate date_time_stamp stream_property string_upper setlocale format
    250   writeln current_module normalize_space writeq current_flag shell upcase_atom
    251   qcompile char_code atomic_concat read string_lower write term_string
    252   numbervars working_directory number_codes set_prolog_gc_thread downcase_atom
    253   format_predicate number_string open_shared_object style_check char_type print
    254   stream_position_data code_type write_canonical number_chars length
    255   current_arithmetic_function atomic_list_concat del_attr read_string zip_unlock
    256   open_resource string_length zip_lock see erase open_resource setof
    257   atomic_list_concat current_format_predicate current_resource with_mutex
    258   atomics_to_string term_hash absolute_file_name deterministic current_atom
    259   thread_create collation_key get_attr variant_hash string_concat atom_number
    260   put put_attr variant_sha1 thread_signal mutex_unlock tty_size current_key
    261   mutex_create fill_buffer expand_file_search_path blob shell
    262   register_iri_scheme skip fast_read divmod mutex_trylock thread_self put
    263   mutex_property fast_write mutex_lock current_blob sub_atom_icasechk
    264   mutex_destroy fast_term_serialized split_string set_stream_position recorda
    265   telling setarg thread_exit zip_open_stream instance mutex_create statistics
    266   append get_time zip_close_ tell atomics_to_string clause_property attvar
    267   zip_clone seeing nth_integer_root_and_remainder recorda put_byte string_chars
    268   spy recordz print_message_lines current_op put_char nl source_file
    269   string_codes op setup_call_catcher_cleanup nb_linkarg recorded put_code
    270   peek_byte apply module_property atom_string nb_setarg succ recordz
    271   message_to_string close_shared_object peek_char between recorded visible plus
    272   call_shared_object_function peek_code peek_byte set_prolog_stack float throw
    273   at_end_of_stream get_string_code call_with_depth_limit random_property
    274   flush_output peek_string open_xterm peek_char open_string string_code
    275   set_random prolog_stack_property put_char unload_file nb_setval put_byte
    276   current_signal put_code write_length string read_string text_to_string
    277 ]]
    278 lex:add_rule('keyword', token(lexer.KEYWORD, word_match(zero_arity_keywords[dialect]) +
    279 	word_match(one_plus_arity_keywords[dialect]) * #P('(')))
    280 
    281 -- BIFs.
    282 local bifs = {}
    283 bifs.iso = [[
    284   -- eyeballed from GNU Prolog documentation
    285   xor abs sign min max sqrt tan atan atan2 cos acos sin asin exp log float
    286   ceiling floor round truncate float_fractional_part float_integer_part rem div
    287   mod
    288 ]]
    289 bifs.gprolog = bifs.iso .. [[
    290   -- eyeballed from GNU Prolog documentation
    291   inc dec lsb msb popcount gcd tanh atanh cosh acosh sinh asinh log10 rnd
    292 ]]
    293 bifs.swipl = [[
    294   -- Collected automatically via current_arithmetic_function/1 with some
    295   -- cleanup.
    296   abs acos acosh asinh atan atan atanh atan2 ceil ceiling copysign cos cosh
    297   cputime div getbit e epsilon erf erfc eval exp float float_fractional_part
    298   float_integer_part floor gcd inf integer lgamma log log10 lsb max min mod msb
    299   nan pi popcount powm random random_float rational rationalize rdiv rem round
    300   sign sin sinh sqrt tan tanh truncate xor
    301 ]]
    302 lex:add_rule('bif', token(lexer.FUNCTION, word_match(bifs[dialect]) * #P('(')))
    303 
    304 -- Numbers.
    305 local decimal_group = S('+-')^-1 * (lexer.digit + '_')^1
    306 local binary_number = '0b' * (S('01') + '_')^1
    307 local character_code = '0\'' * S('\\')^-1 * lexer.graph
    308 local decimal_number = decimal_group * ('.' * decimal_group)^-1 * ('e' * decimal_group)^-1
    309 local hexadecimal_number = '0x' * (lexer.xdigit + '_')^1
    310 local octal_number = '0o' * (S('01234567') + '_')^1
    311 lex:add_rule('number', token(lexer.NUMBER, character_code + binary_number + hexadecimal_number +
    312 	octal_number + decimal_number))
    313 
    314 -- Comments.
    315 local line_comment = lexer.to_eol('%')
    316 local block_comment = lexer.range('/*', '*/')
    317 lex:add_rule('comment', token(lexer.COMMENT, line_comment + block_comment))
    318 
    319 -- Operators.
    320 local operators = {}
    321 operators.iso = [[
    322   -- Collected automatically via current_op/3 with some cleanup and comparison
    323   -- to docs.
    324   rem div mod is
    325 ]]
    326 operators.gprolog = operators.iso -- GNU Prolog's textual operators are the same
    327 operators.swipl = [[
    328   -- Collected automatically via current_op/3 with some cleanup.
    329   is as volatile mod discontiguous div rdiv meta_predicate public xor
    330   module_transparent multifile table dynamic thread_initialization thread_local
    331   initialization rem
    332 ]]
    333 lex:add_rule('operator',
    334 	token(lexer.OPERATOR, word_match(operators[dialect]) + S('-!+\\|=:;&<>()[]{}/*^@?.')))
    335 
    336 -- Variables.
    337 lex:add_rule('variable', token(lexer.VARIABLE,
    338 	(lexer.upper + '_') * (lexer.word^1 + lexer.digit^1 + P('_')^1)^0))
    339 
    340 -- Identifiers.
    341 lex:add_rule('identifier', token(lexer.IDENTIFIER, lexer.word))
    342 
    343 -- Strings.
    344 local sq_str = lexer.range("'", true)
    345 local dq_str = lexer.range('"', true)
    346 lex:add_rule('string', token(lexer.STRING, sq_str + dq_str))
    347 
    348 lexer.property['scintillua.comment'] = '%'
    349 
    350 return lex