Skip to content

Instantly share code, notes, and snippets.

@vermiculus
Last active Aug 29, 2015
Embed
What would you like to do?
\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 }
\rectangle_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
% -*- 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
}
% -*- 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
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment