Skip to content

Instantly share code, notes, and snippets.

@vermiculus
Created July 7, 2015 03:50

Revisions

  1. vermiculus created this gist Jul 7, 2015.
    69 changes: 69 additions & 0 deletions obj-demo.tex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    \nonstopmode \input expl3-generic \relax \ExplSyntaxOn % -*- expl3 -*-

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    \file_input:n { obj }

    \obj_new:nn { rectangle }
    {
    size: int = 2,
    name: tl,
    }

    \rectangle_new:Nn \l_my_rect
    { name = bill }
    \prop_show:N \l_my_rect

    \exp_args:No \msg_term:n { name=\rectangle_get:Nn \l_my_rect {name} }

    \rectangle_set:Nn \l_my_rect { name = bob, other=hi }

    \exp_args:No \msg_term:n { name=\rectangle_get:Nn \l_my_rect {name} }
    \obj_show:n { rectangle }

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    \msg_term:n { Testing~ball... }

    \obj_new:nn { ball }
    {
    bounce-factor: int = 4,
    name: tl,
    color: color = blue,
    }

    \obj_show:n { ball }

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    \msg_term:n { Creating~a~ball... }

    \ball_new:Nn \l_my_ball
    {
    name = hello,
    color = red,
    }

    \exp_args:No \msg_term:n { \ball_get:Nn \l_my_ball { name } }

    \ball_show:N \l_my_ball

    \msg_term:n { Testing~ball...complete. }

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    \msg_term:n { Testing~baseball... }

    \obj_new:nn { ball / baseball }
    {
    games-won: int = 0,
    stiches: int,
    }

    \obj_show:n { baseball }

    \msg_term:n { Testing~baseball...complete. }

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    \bye
    176 changes: 176 additions & 0 deletions obj.tex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,176 @@
    % -*- expl3 -*-

    \file_input:n { parsing }

    \tl_new:N \l__obj_tmp_tl
    \seq_new:N \l__obj_tmp_seq

    \clist_new:N \g__obj_obj__types_clist
    \clist_set:Nn \g__obj_obj__types_clist
    { obj, tl, seq, int, color }

    \msg_new:nnn { obj } { unknown-type }
    { The~type~you~have~provided~is~not~known~to~exist:~`#1' }

    \msg_new:nnn { obj } { unknown-field }
    { The~field~you~have~provided~is~not~known~to~exist~for~this~object:~`#1.#2' }

    % \section{Methods, Getters, and Setters}

    \cs_new:Nn \obj_method:nnn { \cs_new:cn { #1_#2 } {#3} }
    \cs_new:Nn \obj_use_method:nn { \use:c { #1_#2 } }
    \cs_new:Nn \__obj_make_getter:nn
    { \obj_method:nnn {#1} { #2:N } { \prop_item:Nn ##1 {#2} } }
    \cs_new:Nn \__obj_make_setter:nn
    { \obj_method:nnn {#1} { #2:Nn } { \prop_put:Nnn ##1 {#2} {##2} } }

    \cs_generate_variant:Nn \__obj_make_getter:nn { VV }
    \cs_generate_variant:Nn \__obj_make_setter:nn { VV }

    % \section{Defining New Objects}

    % \subsection{Internal Storage}
    \cs_new:Nn \__obj_setup:nNN % with superclass
    { % { {spec} {proto} }
    \seq_new:c { g__obj_spec_#1_seq }
    \seq_put_left:cV { g__obj_spec_#1_seq } #2
    \seq_put_right:cV { g__obj_spec_#1_seq } #3
    }
    \cs_new:Nn \__obj_setup:n % no superclass
    { \__obj_setup:nNN {#1} \c_empty_prop \c_empty_prop }

    \cs_generate_variant:Nn \__obj_setup:n { V }
    \cs_generate_variant:Nn \__obj_setup:nNN { V }

    \cs_new:Nn \__obj_spec:nN { \seq_get_left:cN { g__obj_spec_#1_seq } #2 } % get spec
    \cs_new:Nn \__obj_proto:nN { \seq_get_right:cN { g__obj_spec_#1_seq } #2 } % get proto
    \cs_new:Nn \__obj_spec:Nn % set spec
    {
    \seq_pop_left:cN { g__obj_spec_#2_seq } \l__obj_tmp_seq
    \seq_put_left:cV { g__obj_spec_#2_seq } #1
    }
    \cs_new:Nn \__obj_proto:Nn % set proto
    {
    \seq_pop_right:cN { g__obj_spec_#2_seq } \l__obj_tmp_seq
    \seq_put_right:cV { g__obj_spec_#2_seq } #1
    }

    \cs_generate_variant:Nn \__obj_spec:nN { V }
    \cs_generate_variant:Nn \__obj_proto:nN { V }
    \cs_generate_variant:Nn \__obj_spec:Nn { NV }
    \cs_generate_variant:Nn \__obj_proto:Nn { NV }

    % \subsection{User Interface}

    \tl_new:N \l__obj_class_name_tl
    \cs_new:Nn \obj_new:nn
    {
    \__obj_define:nnN {#1} {#2} \l__obj_class_name_tl
    \__obj_process_fields:Vn \l__obj_class_name_tl {#2}
    \__obj_make_metas:V \l__obj_class_name_tl
    }

    \prop_new:N \l__obj_spec_prop
    \prop_new:N \l__obj_proto_prop
    \cs_new:Nn \__obj_define:nnN % { { super / class } class-name-tl-var }
    {
    \seq_set_split:Nnn \l__obj_tmp_seq { / } {#1}
    \seq_pop_right:NN \l__obj_tmp_seq #3 % class
    \seq_pop_right:NN \l__obj_tmp_seq \l__obj_tmp_tl % superclass
    \quark_if_no_value:NTF \l__obj_tmp_tl
    { \__obj_setup:V #3 }
    {
    % grab superclass spec, prototype
    \__obj_spec:VN \l__obj_tmp_tl \l__obj_spec_prop
    \__obj_proto:VN \l__obj_tmp_tl \l__obj_proto_prop
    % and base the new object off of it
    \__obj_setup:VNN #3 \l__obj_spec_prop \l__obj_proto_prop

    % get the prototype for the new class
    \__obj_proto:VN \l__obj_tmp_tl \l__obj_tmp_prop
    \parse_dictionary:nn {#2}
    {
    \prop_if_in:NVF \l__obj_proto_prop \l_parse_dictionary_key_tl
    {
    \prop_put:NVV \l__obj_tmp_prop
    \l_parse_dictionary_key_tl
    \l_parse_dictionary_value_tl
    }
    }
    \__obj_proto:NV \l__obj_tmp_prop \l__obj_tmp_tl
    }
    }

    \cs_new:Nn \__obj_process_fields:nn % { {class-name} {fields} }
    {
    \parse_dictionary:nn {#2}
    {
    % make sure we know about this type
    \clist_if_in:NVF
    \g__obj_obj__types_clist
    \l_parse_dictionary_type_tl
    {
    \msg_warning:nnx { obj } { unknown-type }
    { \tl_use:N \l_parse_dictionary_type_tl }
    }
    \__obj_spec:nN {#1} \l__obj_tmp_prop
    \prop_put:NVV \l__obj_tmp_prop
    \l_parse_dictionary_key_tl
    \l_parse_dictionary_type_tl
    \__obj_spec:Nn \l__obj_tmp_prop {#1}

    \__obj_proto:nN {#1} \l__obj_tmp_prop
    \prop_put:NVV \l__obj_tmp_prop
    \l_parse_dictionary_key_tl
    \l_parse_dictionary_value_tl
    \__obj_proto:Nn \l__obj_tmp_prop {#1}
    }
    }
    \cs_generate_variant:Nn \__obj_process_fields:nn { V }

    \cs_new:Nn \__obj_make_metas:n
    {
    \obj_method:nnn {#1} { show:N } { \prop_show:N ##1 }
    \obj_method:nnn {#1} { new:N } % { obj-var }
    {
    \__obj_proto:nN {#1} \l__obj_tmp_prop
    \prop_set_eq:NN ##1 \l__obj_tmp_prop
    }

    \obj_method:nnn {#1} { new:Nn } % { obj-var {values} }
    {
    \obj_use_method:nn {#1} { new:N } ##1
    \obj_use_method:nn {#1} { set:Nn } ##1 {##2}
    % put in defaults
    \__obj_proto:nN {#1} \l__obj_tmp_prop
    \prop_map_inline:Nn \l__obj_tmp_prop
    { \prop_put_if_new:Nnn ##1 {####1} {####2} }
    }

    \obj_method:nnn {#1} { get:Nn } % { obj-var {field} }
    { \prop_item:Nn ##1 {##2} }

    \obj_method:nnn {#1} { set:Nn }
    {
    \prop_clear_new:N ##1
    \__obj_spec:nN {#1} \l__obj_tmp_prop
    \parse_prop:nn {##2}
    {
    \prop_if_in:NVF \l__obj_tmp_prop \l_parse_prop_key_tl
    {
    \msg_warning:nnxx { obj } { unknown-field } {#1}
    { \tl_use:N \l_parse_prop_key_tl }
    }
    \prop_put:NVV ##1 \l_parse_prop_key_tl \l_parse_prop_value_tl
    }
    }
    }
    \cs_generate_variant:Nn \__obj_make_metas:n { V }

    \cs_new:Nn \obj_show:n
    {
    \__obj_spec:nN {#1} \l__obj_tmp_prop
    \prop_show:N \l__obj_tmp_prop
    \__obj_proto:nN {#1} \l__obj_tmp_prop
    \prop_show:N \l__obj_tmp_prop
    }
    44 changes: 44 additions & 0 deletions parsing.tex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,44 @@
    % -*- expl3 -*-

    \tl_new:N \l_parse_dictionary_key_tl
    \tl_new:N \l_parse_dictionary_type_tl
    \tl_new:N \l_parse_dictionary_value_tl
    \seq_new:N \l__parse_dictionary_dict_seq
    \seq_new:N \l__parse_dictionary_field_seq
    \cs_new:Nn \parse_dictionary:nn
    {
    \seq_set_split:Nnn \l__parse_dictionary_dict_seq { , } {#1}
    \seq_map_inline:Nn \l__parse_dictionary_dict_seq
    {
    \tl_if_empty:nF {##1}
    {
    \seq_set_split:Nnn \l__parse_dictionary_field_seq { : } {##1}
    \seq_pop:NN \l__parse_dictionary_field_seq \l_parse_dictionary_key_tl
    \seq_pop:NN \l__parse_dictionary_field_seq \l_parse_dictionary_type_tl
    \seq_set_split:NnV \l__parse_dictionary_field_seq { = } \l_parse_dictionary_type_tl
    \seq_pop:NN \l__parse_dictionary_field_seq \l_parse_dictionary_type_tl
    \seq_pop:NNF \l__parse_dictionary_field_seq \l_parse_dictionary_value_tl
    { \tl_clear:N \l_parse_dictionary_value_tl }
    #2
    }
    }
    }

    \tl_new:N \l_parse_prop_key_tl
    \tl_new:N \l_parse_prop_value_tl
    \seq_new:N \l__parse_prop_dict_seq
    \seq_new:N \l__parse_prop_field_seq
    \cs_new:Nn \parse_prop:nn
    {
    \seq_set_split:Nnn \l__parse_prop_dict_seq { , } {#1}
    \seq_map_inline:Nn \l__parse_prop_dict_seq
    {
    \tl_if_empty:nF {##1}
    {
    \seq_set_split:Nnn \l__parse_prop_field_seq { = } {##1}
    \seq_pop:NN \l__parse_prop_field_seq \l_parse_prop_key_tl
    \seq_pop:NN \l__parse_prop_field_seq \l_parse_prop_value_tl
    #2
    }
    }
    }