//: Introduce a new transform to perform various checks in instructions before //: we start running them. It'll be extensible, so that we can add checks for //: new recipes as we extend 'run' to support them. //: //: Doing checking in a separate part complicates things, because the values //: of variables in memory and the processor (current_recipe_name, //: current_instruction) aren't available at checking time. If I had a more //: sophisticated layer system I'd introduce the simpler version first and //: transform it in a separate layer or set of layers. :(before "End Checks") Transform.push_back(check_instruction); // idempotent :(code) void check_instruction(const recipe_ordinal r) { trace(9991, "transform") << "--- perform checks for recipe " << get(Recipe, r).name << end(); //? cerr << "--- perform checks for recipe " << get(Recipe, r).name << '\n'; map<string, vector<type_ordinal> > metadata; for (long long int i = 0; i < SIZE(get(Recipe, r).steps); ++i) { instruction& inst = get(Recipe, r).steps.at(i); if (inst.is_label) continue; switch (inst.operation) { // Primitive Recipe Checks case COPY: { if (SIZE(inst.products) != SIZE(inst.ingredients)) { raise_error << "ingredients and products should match in '" << inst.to_string() << "'\n" << end(); break; } for (long long int i = 0; i < SIZE(inst.ingredients); ++i) { if (!types_coercible(inst.products.at(i), inst.ingredients.at(i))) { raise_error << maybe(get(Recipe, r).name) << "can't copy " << inst.ingredients.at(i).original_string << " to " << inst.products.at(i).original_string << "; types don't match\n" << end(); goto finish_checking_instruction; } } break; } // End Primitive Recipe Checks default: { // Defined Recipe Checks // End Defined Recipe Checks } } finish_checking_instruction:; } } :(scenario copy_checks_reagent_count) % Hide_errors = true; recipe main [ 1:number <- copy 34, 35 ] +error: ingredients and products should match in '1:number <- copy 34, 35' :(scenario write_scalar_to_array_disallowed) % Hide_errors = true; recipe main [ 1:array:number <- copy 34 ] +error: main: can't copy 34 to 1:array:number; types don't match :(scenario write_scalar_to_array_disallowed_2) % Hide_errors = true; recipe main [ 1:number, 2:array:number <- copy 34, 35 ] +error: main: can't copy 35 to 2:array:number; types don't match :(scenario write_scalar_to_address_disallowed) % Hide_errors = true; recipe main [ 1:address:number <- copy 34 ] +error: main: can't copy 34 to 1:address:number; types don't match :(scenario write_address_to_number_allowed) % Hide_errors = true; recipe main [ 1:address:number <- copy 12/unsafe 2:number <- copy 1:address:number ] +mem: storing 12 in location 2 $error: 0 :(code) // types_match with some leniency bool types_coercible(const reagent& lhs, const reagent& rhs) { if (types_match(lhs, rhs)) return true; if (is_mu_address(rhs) && is_mu_number(lhs)) return true; // End types_coercible Special-cases return false; } bool types_match(const reagent& lhs, const reagent& rhs) { // to sidestep type-checking, use /unsafe in the source. // this will be highlighted in red inside vim. just for setting up some tests. if (is_unsafe(rhs)) return true; if (is_literal(rhs)) { if (is_mu_array(lhs)) return false; // End Matching Types For Literal(lhs) // allow writing 0 to any address if (is_mu_address(lhs)) return rhs.name == "0"; if (!lhs.type) return false; if (lhs.type->value == get(Type_ordinal, "boolean")) return boolean_matches_literal(lhs, rhs); return size_of(lhs) == 1; // literals are always scalars } return types_strictly_match(lhs, rhs); } bool boolean_matches_literal(const reagent& lhs, const reagent& rhs) { if (!is_literal(rhs)) return false; if (!lhs.type) return false; if (lhs.type->value != get(Type_ordinal, "boolean")) return false; return rhs.name == "0" || rhs.name == "1"; } // copy arguments because later layers will want to make changes to them // without perturbing the caller bool types_strictly_match# Common Makefile for W3 Library Code # ----------------------------------- # # (c) CERN 1990, 1991 -- see Copyright.html for conditions # # This file should be invariant between systems. # DEPENDENCIES NOT COMPLETE @@ # # make Compile and link the software (private version) # make install Copy it into the system (implies make) # make update Copy installed version into installed version # make uninstall Unlink installed version from the system # make clean Remove intermediate files # make cleanall Remove intremediate files and products # # Macros required to be defined already for make: # # CC The C compiler # CFLAGS Flags for $(CC) -- except the -I which are below # LFLAGS Flags for ld # LYFLAGS Flags for Lynx # # WWW The WWW source tree directory # # Macros needed for make install: # # LIBDIR Directory for installed library #______________________________________________________________________ # If this env var is set to something else Some makes will use that instead SHELL = /bin/sh # .h files are distributed but originally are made from the # self-documenting hypertext files. .SUFFIXES: .h .html .htm .html.h: # - chmod +w $*.h # www -w90 -na -to text/x-c $*.html > $*.h # chmod -w $*.h # If this is actually run in a subdirectory, # WWW = ../.. # WWW = ../.. For [cernlib] build in this directory WC = $(WWW)/Library CMN = $(WWW)/Library/Implementation/ VMS = $(CMN)vms # Where shall we put the objects and built library? LOB = $(WTMP)/Library/$(WWW_MACH) # Only needed if HTWAIS.c is to be compiled. Put into your Makefile.include # uncomment these and fill in WAISINC for adding direct wais access # to Lynx. #HTWAIS = $(LOB)/HTWAIS.o #WAIS = YES #WAISINC = -I../../../../freeWAIS-0.202/ir #WAISCFLAGS = -DDIRECT_WAIS # # This path, if relative, is taken relative to the directory # in which this makefile is, not the pwd. This screws up the # recursive invocation # include $(CMN)Version.make include $(ABS)$(WWW)/Library/Implementation/Version.make # XMOsAIC hack is only for server to cope with xmosaic kludge for mmedia # # add -DNEW_GATEWAY here for the new gateway config stuff CFLAGS2 = $(CFLAGS) $(LYFLAGS) $(WAISCFLAGS) -I$(CMN) -DXMOSAIC_HACK -DACCESS_AUTH CERNLIBBIN = $(WWW)/bin COMMON = $(LOB)/HTParse.o $(LOB)/HTAccess.o $(LOB)/HTTP.o \ $(LOB)/HTFile.o $(LOB)/HTBTree.o $(LOB)/HTFTP.o $(LOB)/HTTCP.o \ $(LOB)/SGML.o $(LOB)/HTMLDTD.o $(LOB)/HTChunk.o \ $(LOB)/HTPlain.o \ $(LOB)/HTMLGen.o \ $(LOB)/HTAtom.o $(LOB)/HTAnchor.o $(LOB)/HTStyle.o \ $(LOB)/HTList.o $(LOB)/HTString.o $(LOB)/HTDOS.o \ $(LOB)/HTRules.o $(LOB)/HTFormat.o $(LOB)/HTMIME.o \ $(LOB)/HTNews.o $(LOB)/HTGopher.o \ $(LOB)/HTTelnet.o $(LOB)/HTFinger.o $(LOB)/HTWSRC.o $(HTWAIS) \ $(LOB)/HTAAUtil.o $(LOB)/HTAABrow.o \ $(LOB)/HTGroup.o \ $(LOB)/HTAAProt.o \ $(LOB)/HTAssoc.o $(LOB)/HTLex.o $(LOB)/HTUU.o CFILES = $(CMN)HTParse.c $(CMN)HTAccess.c $(CMN)HTTP.c $(CMN)HTFile.c \ $(CMN)HTBTree.c \ $(CMN)HTFTP.c $(CMN)HTTCP.c $(CMN)SGML.c \ $(CMN)HTMLDTD.c \ $(CMN)HTPlain.c \ $(CMN)HTDOS.c $(CMN)HTMLGen.c \ $(CMN)HTChunk.c $(CMN)HTAtom.c $(CMN)HTAnchor.c $(CMN)HTStyle.c \ $(CMN)HTList.c $(CMN)HTString.c $(CMN)HTRules.c \ $(CMN)HTFormat.c $(CMN)HTMIME.c \ $(CMN)HTNews.c $(CMN)HTGopher.c $(CMN)HTTelnet.c \ $(CMN)HTFinger.c $(CMN)HTWAIS.c $(CMN)HTWSRC.c \ $(CMN)HTAAUtil.c $(CMN)HTAABrow.c \ $(CMN)HTGroup.c \ $(CMN)HTAAProt.c \ $(CMN)HTAssoc.c $(CMN)HTLex.c $(CMN)HTUU.c HFILES = $(CMN)HTParse.h $(CMN)HTAccess.h $(CMN)HTTP.h $(CMN)HTFile.h \ $(CMN)HTBTree.h $(CMN)HTFTP.h $(CMN)HTTCP.h \ $(CMN)SGML.h $(CMN)HTML.h $(CMN)HTMLDTD.h $(CMN)HTChunk.h \ $(CMN)HTPlain.h \ $(CMN)HTFWriter.h $(CMN)HTMLGen.h $(CMN)HTDOS.h \ $(CMN)HTStream.h \ $(CMN)HTAtom.h $(CMN)HTAnchor.h $(CMN)HTStyle.h \ $(CMN)HTList.h \ $(CMN)HTString.h $(CMN)HTRules.h \