Merge pull request #1635 from mthom/rebis-dev
Some checks failed
Test / windows (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
Test / build (macos-10.15, beta) (push) Has been cancelled
Test / build (macos-10.15, stable) (push) Has been cancelled
Test / build (ubuntu-20.04, beta) (push) Has been cancelled
Test / build (ubuntu-20.04, stable) (push) Has been cancelled
Test / msrv (macos-10.15) (push) Has been cancelled
Test / msrv (ubuntu-20.04) (push) Has been cancelled

Merge rebis-dev into master
This commit is contained in:
Mark Thom
2022-11-10 07:18:10 +01:00
committed by GitHub
63 changed files with 5194 additions and 2563 deletions

View File

@@ -52,3 +52,20 @@ jobs:
crate: cargo-msrv crate: cargo-msrv
- name: Verify MSRV - name: Verify MSRV
run: cargo msrv --verify run: cargo msrv --verify
windows:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
update: true
install: >-
base-devel
mingw-w64-x86_64-rust
- name: Checkout sources
uses: actions/checkout@v3
- name: Test on Windows
run: cargo test --verbose --all

980
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.9.0" version = "0.9.1"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021" edition = "2021"
description = "A modern Prolog implementation written mostly in Rust." description = "A modern Prolog implementation written mostly in Rust."
@@ -10,13 +10,9 @@ license = "BSD-3-Clause"
keywords = ["prolog", "prolog-interpreter", "prolog-system"] keywords = ["prolog", "prolog-interpreter", "prolog-system"]
categories = ["command-line-utilities"] categories = ["command-line-utilities"]
build = "build/main.rs" build = "build/main.rs"
rust-version = "1.57" rust-version = "1.61"
[features] [features]
num = ["num-rug-adapter"]
# no default features to make num tests work
# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
# see rust-lang/cargo#7160
default = ["rug"] default = ["rug"]
[build-dependencies] [build-dependencies]
@@ -44,7 +40,6 @@ lexical = "5.2.2"
libc = "0.2.62" libc = "0.2.62"
modular-bitfield = "0.11.2" modular-bitfield = "0.11.2"
ctrlc = "3.2.2" ctrlc = "3.2.2"
num-rug-adapter = { version = "0.1.6", optional = true }
ordered-float = "2.6.0" ordered-float = "2.6.0"
phf = { version = "0.9", features = ["macros"] } phf = { version = "0.9", features = ["macros"] }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
@@ -54,7 +49,7 @@ ring = "0.16.13"
ripemd160 = "0.8.0" ripemd160 = "0.8.0"
sha3 = "0.8.2" sha3 = "0.8.2"
blake2 = "0.8.1" blake2 = "0.8.1"
openssl = { version = "0.10.29", features = ["vendored"] } crrl ="0.2.0"
native-tls = "0.2.4" native-tls = "0.2.4"
chrono = "0.4.11" chrono = "0.4.11"
select = "0.4.3" select = "0.4.3"
@@ -67,6 +62,7 @@ ryu = "1.0.9"
hyper = { version = "0.14", features = ["full"] } hyper = { version = "0.14", features = ["full"] }
hyper-tls = "0.5.0" hyper-tls = "0.5.0"
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
futures = "0.3"
[dev-dependencies] [dev-dependencies]
assert_cmd = "1.0.3" assert_cmd = "1.0.3"
@@ -75,7 +71,6 @@ serial_test = "0.5.1"
[patch.crates-io] [patch.crates-io]
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" }
num-rug-adapter = { git = "https://github.com/mthom/num-rug-adapter" }
[profile.release] [profile.release]
debug = true debug = true

View File

@@ -539,7 +539,7 @@ The modules that ship with Scryer&nbsp;Prolog are also called
Probabilistic predicates and random number generators. Probabilistic predicates and random number generators.
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to * [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
read answers from web&nbsp;servers. HTTPS is also supported. read answers from web&nbsp;servers. HTTPS is also supported.
* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.0 web server. * [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Hyper](https://hyper.rs) as a backend. Supports some query and form handling.
* [`sgml`](src/lib/sgml.pl) * [`sgml`](src/lib/sgml.pl)
`load_html/3` and `load_xml/3` represent HTML and XML&nbsp;documents `load_html/3` and `load_xml/3` represent HTML and XML&nbsp;documents
as Prolog&nbsp;terms for convenient and efficient reasoning. Use as Prolog&nbsp;terms for convenient and efficient reasoning. Use

View File

@@ -190,9 +190,9 @@ enum REPLCodePtr {
DynamicProperty, DynamicProperty,
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
AbolishClause, AbolishClause,
#[strum_discriminants(strum(props(Arity = "5", Name = "$asserta")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
Asserta, Asserta,
#[strum_discriminants(strum(props(Arity = "5", Name = "$assertz")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
Assertz, Assertz,
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
Retract, Retract,
@@ -404,8 +404,6 @@ enum SystemClauseType {
InferenceLevel, InferenceLevel,
#[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))]
CleanUpBlock, CleanUpBlock,
#[strum_discriminants(strum(props(Arity = "0", Name = "$erase_ball")))]
EraseBall,
#[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))] #[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))]
Fail, Fail,
#[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))]
@@ -434,6 +432,12 @@ enum SystemClauseType {
ReturnFromVerifyAttr, ReturnFromVerifyAttr,
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))]
SetBall, SetBall,
#[strum_discriminants(strum(props(Arity = "0", Name = "$push_ball_stack")))]
PushBallStack,
#[strum_discriminants(strum(props(Arity = "0", Name = "$pop_ball_stack")))]
PopBallStack,
#[strum_discriminants(strum(props(Arity = "0", Name = "$pop_from_ball_stack")))]
PopFromBallStack,
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))]
SetCutPointByDefault(RegType), SetCutPointByDefault(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))]
@@ -492,7 +496,7 @@ enum SystemClauseType {
CryptoDataEncrypt, CryptoDataEncrypt,
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))] #[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
CryptoDataDecrypt, CryptoDataDecrypt,
#[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_curve_scalar_mult")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_curve_scalar_mult")))]
CryptoCurveScalarMult, CryptoCurveScalarMult,
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
Ed25519Sign, Ed25519Sign,
@@ -544,10 +548,22 @@ enum SystemClauseType {
DeterministicLengthRundown, DeterministicLengthRundown,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))] #[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))]
HttpOpen, HttpOpen,
#[strum_discriminants(strum(props(Arity = "2", Name = "$http_listen")))]
HttpListen,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))]
HttpAccept,
#[strum_discriminants(strum(props(Arity = "4", Name = "$http_answer")))]
HttpAnswer,
#[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
PredicateDefined, PredicateDefined,
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
StripModule, StripModule,
#[strum_discriminants(strum(props(Arity = "4", Name = "$compile_inline_or_expanded_goal")))]
CompileInlineOrExpandedGoal,
#[strum_discriminants(strum(props(Arity = "arity", Name = "$call_inline")))]
InlineCallN(usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "$is_expanded_or_inlined")))]
IsExpandedOrInlined,
REPL(REPLCodePtr), REPL(REPLCodePtr),
} }
@@ -1435,6 +1451,12 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultExecuteN(arity, _) => { &Instruction::DefaultExecuteN(arity, _) => {
functor!(atom!("execute_default_n"), [fixnum(arity)]) functor!(atom!("execute_default_n"), [fixnum(arity)])
} }
&Instruction::CallInlineCallN(arity, _) => {
functor!(atom!("call_n_inline"), [fixnum(arity)])
}
&Instruction::ExecuteInlineCallN(arity, _) => {
functor!(atom!("call_n_inline"), [fixnum(arity)])
}
&Instruction::CallTermGreaterThan(_) | &Instruction::CallTermGreaterThan(_) |
&Instruction::CallTermLessThan(_) | &Instruction::CallTermLessThan(_) |
&Instruction::CallTermGreaterThanOrEqual(_) | &Instruction::CallTermGreaterThanOrEqual(_) |
@@ -1597,6 +1619,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallDeleteHeadAttribute(_) | &Instruction::CallDeleteHeadAttribute(_) |
&Instruction::CallDynamicModuleResolution(..) | &Instruction::CallDynamicModuleResolution(..) |
&Instruction::CallPrepareCallClause(..) | &Instruction::CallPrepareCallClause(..) |
&Instruction::CallCompileInlineOrExpandedGoal(..) |
&Instruction::CallIsExpandedOrInlined(_) |
&Instruction::CallEnqueueAttributedVar(_) | &Instruction::CallEnqueueAttributedVar(_) |
&Instruction::CallFetchGlobalVar(_) | &Instruction::CallFetchGlobalVar(_) |
&Instruction::CallFirstStream(_) | &Instruction::CallFirstStream(_) |
@@ -1660,7 +1684,6 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallSetStreamPosition(_) | &Instruction::CallSetStreamPosition(_) |
&Instruction::CallInferenceLevel(_) | &Instruction::CallInferenceLevel(_) |
&Instruction::CallCleanUpBlock(_) | &Instruction::CallCleanUpBlock(_) |
&Instruction::CallEraseBall(_) |
&Instruction::CallFail(_) | &Instruction::CallFail(_) |
&Instruction::CallGetBall(_) | &Instruction::CallGetBall(_) |
&Instruction::CallGetCurrentBlock(_) | &Instruction::CallGetCurrentBlock(_) |
@@ -1672,6 +1695,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallCpuNow(_) | &Instruction::CallCpuNow(_) |
&Instruction::CallDeterministicLengthRundown(_) | &Instruction::CallDeterministicLengthRundown(_) |
&Instruction::CallHttpOpen(_) | &Instruction::CallHttpOpen(_) |
&Instruction::CallHttpListen(_) |
&Instruction::CallHttpAccept(_) |
&Instruction::CallHttpAnswer(_) |
&Instruction::CallPredicateDefined(_) | &Instruction::CallPredicateDefined(_) |
&Instruction::CallStripModule(_) | &Instruction::CallStripModule(_) |
&Instruction::CallCurrentTime(_) | &Instruction::CallCurrentTime(_) |
@@ -1680,6 +1706,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallResetBlock(_) | &Instruction::CallResetBlock(_) |
&Instruction::CallReturnFromVerifyAttr(_) | &Instruction::CallReturnFromVerifyAttr(_) |
&Instruction::CallSetBall(_) | &Instruction::CallSetBall(_) |
&Instruction::CallPushBallStack(_) |
&Instruction::CallPopBallStack(_) |
&Instruction::CallPopFromBallStack(_) |
&Instruction::CallSetCutPointByDefault(..) | &Instruction::CallSetCutPointByDefault(..) |
&Instruction::CallSetDoubleQuotes(_) | &Instruction::CallSetDoubleQuotes(_) |
&Instruction::CallSetSeed(_) | &Instruction::CallSetSeed(_) |
@@ -1804,6 +1833,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteDeleteHeadAttribute(_) | &Instruction::ExecuteDeleteHeadAttribute(_) |
&Instruction::ExecuteDynamicModuleResolution(..) | &Instruction::ExecuteDynamicModuleResolution(..) |
&Instruction::ExecutePrepareCallClause(..) | &Instruction::ExecutePrepareCallClause(..) |
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
&Instruction::ExecuteIsExpandedOrInlined(_) |
&Instruction::ExecuteEnqueueAttributedVar(_) | &Instruction::ExecuteEnqueueAttributedVar(_) |
&Instruction::ExecuteFetchGlobalVar(_) | &Instruction::ExecuteFetchGlobalVar(_) |
&Instruction::ExecuteFirstStream(_) | &Instruction::ExecuteFirstStream(_) |
@@ -1867,7 +1898,6 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteSetStreamPosition(_) | &Instruction::ExecuteSetStreamPosition(_) |
&Instruction::ExecuteInferenceLevel(_) | &Instruction::ExecuteInferenceLevel(_) |
&Instruction::ExecuteCleanUpBlock(_) | &Instruction::ExecuteCleanUpBlock(_) |
&Instruction::ExecuteEraseBall(_) |
&Instruction::ExecuteFail(_) | &Instruction::ExecuteFail(_) |
&Instruction::ExecuteGetBall(_) | &Instruction::ExecuteGetBall(_) |
&Instruction::ExecuteGetCurrentBlock(_) | &Instruction::ExecuteGetCurrentBlock(_) |
@@ -1879,6 +1909,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteCpuNow(_) | &Instruction::ExecuteCpuNow(_) |
&Instruction::ExecuteDeterministicLengthRundown(_) | &Instruction::ExecuteDeterministicLengthRundown(_) |
&Instruction::ExecuteHttpOpen(_) | &Instruction::ExecuteHttpOpen(_) |
&Instruction::ExecuteHttpListen(_) |
&Instruction::ExecuteHttpAccept(_) |
&Instruction::ExecuteHttpAnswer(_) |
&Instruction::ExecutePredicateDefined(_) | &Instruction::ExecutePredicateDefined(_) |
&Instruction::ExecuteStripModule(_) | &Instruction::ExecuteStripModule(_) |
&Instruction::ExecuteCurrentTime(_) | &Instruction::ExecuteCurrentTime(_) |
@@ -1887,6 +1920,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteResetBlock(_) | &Instruction::ExecuteResetBlock(_) |
&Instruction::ExecuteReturnFromVerifyAttr(_) | &Instruction::ExecuteReturnFromVerifyAttr(_) |
&Instruction::ExecuteSetBall(_) | &Instruction::ExecuteSetBall(_) |
&Instruction::ExecutePushBallStack(_) |
&Instruction::ExecutePopBallStack(_) |
&Instruction::ExecutePopFromBallStack(_) |
&Instruction::ExecuteSetCutPointByDefault(_, _) | &Instruction::ExecuteSetCutPointByDefault(_, _) |
&Instruction::ExecuteSetDoubleQuotes(_) | &Instruction::ExecuteSetDoubleQuotes(_) |
&Instruction::ExecuteSetSeed(_) | &Instruction::ExecuteSetSeed(_) |
@@ -2179,6 +2215,7 @@ pub fn generate_instructions_rs() -> TokenStream {
let mut clause_type_from_name_and_arity_arms = vec![]; let mut clause_type_from_name_and_arity_arms = vec![];
let mut clause_type_to_instr_arms = vec![]; let mut clause_type_to_instr_arms = vec![];
let mut clause_type_name_arms = vec![]; let mut clause_type_name_arms = vec![];
let mut is_inbuilt_arms = vec![];
for (name, arity, variant) in instr_data.compare_number_variants { for (name, arity, variant) in instr_data.compare_number_variants {
let ident = variant.ident.clone(); let ident = variant.ident.clone();
@@ -2233,6 +2270,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(#(#placeholder_ids),*, 0) ) => Instruction::#instr_ident(#(#placeholder_ids),*, 0)
} }
); );
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.compare_term_variants { for (name, arity, variant) in instr_data.compare_term_variants {
@@ -2262,6 +2305,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(0) ) => Instruction::#instr_ident(0)
} }
); );
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.builtin_type_variants { for (name, arity, variant) in instr_data.builtin_type_variants {
@@ -2323,6 +2372,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(0) ) => Instruction::#instr_ident(0)
} }
}); });
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.inlined_type_variants { for (name, arity, variant) in instr_data.inlined_type_variants {
@@ -2382,6 +2437,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(#(#placeholder_ids),*,0) ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
} }
); );
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.system_clause_type_variants { for (name, arity, variant) in instr_data.system_clause_type_variants {
@@ -2412,6 +2473,12 @@ pub fn generate_instructions_rs() -> TokenStream {
SystemClauseType::#ident(temp_v!(1)) SystemClauseType::#ident(temp_v!(1))
) )
} }
} else if ident.to_string() == "InlineCallN" {
quote! {
(atom!(#name), arity) => ClauseType::System(
SystemClauseType::#ident(arity)
)
}
} else { } else {
quote! { quote! {
(atom!(#name), #arity) => ClauseType::System( (atom!(#name), #arity) => ClauseType::System(
@@ -2442,6 +2509,7 @@ pub fn generate_instructions_rs() -> TokenStream {
}); });
let ident = variant.ident; let ident = variant.ident;
let instr_ident = if ident != "CallContinuation" { let instr_ident = if ident != "CallContinuation" {
format_ident!("Call{}", ident) format_ident!("Call{}", ident)
} else { } else {
@@ -2465,6 +2533,18 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(0) ) => Instruction::#instr_ident(0)
} }
}); });
is_inbuilt_arms.push(
if let Arity::Ident("arity") = &arity {
quote! {
(atom!(#name), _arity) => true
}
} else {
quote! {
(atom!(#name), #arity) => true
}
}
);
} }
for (name, arity, variant) in instr_data.repl_code_ptr_variants { for (name, arity, variant) in instr_data.repl_code_ptr_variants {
@@ -2530,6 +2610,12 @@ pub fn generate_instructions_rs() -> TokenStream {
)) => Instruction::#instr_ident(0) )) => Instruction::#instr_ident(0)
} }
}); });
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.clause_type_variants { for (name, arity, variant) in instr_data.clause_type_variants {
@@ -2537,7 +2623,7 @@ pub fn generate_instructions_rs() -> TokenStream {
if ident == "Named" { if ident == "Named" {
clause_type_from_name_and_arity_arms.push(quote! { clause_type_from_name_and_arity_arms.push(quote! {
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default()) (name, arity) => ClauseType::Named(arity, name, CodeIndex::default(arena))
}); });
clause_type_to_instr_arms.push(quote! { clause_type_to_instr_arms.push(quote! {
@@ -2599,6 +2685,12 @@ pub fn generate_instructions_rs() -> TokenStream {
ClauseType::#ident => Instruction::#ident(0) ClauseType::#ident => Instruction::#ident(0)
} }
}); });
is_inbuilt_arms.push(
quote! {
(atom!(#name), _arity) => true
}
);
} }
let to_execute_arms: Vec<_> = instr_data.instr_variants let to_execute_arms: Vec<_> = instr_data.instr_variants
@@ -2933,7 +3025,7 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
impl ClauseType { impl ClauseType {
pub fn from(name: Atom, arity: usize) -> ClauseType { pub fn from(name: Atom, arity: usize, arena: &mut Arena) -> ClauseType {
match (name, arity) { match (name, arity) {
#( #(
#clause_type_from_name_and_arity_arms, #clause_type_from_name_and_arity_arms,
@@ -2949,19 +3041,12 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
} }
pub fn is_builtin(&self) -> bool { pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
if let ClauseType::BuiltIn(_) = self { match (name, arity) {
true #(
} else { #is_inbuilt_arms,
false )*
} _ => false,
}
pub fn is_inlined(&self) -> bool {
if let ClauseType::Inlined(_) = self {
true
} else {
false
} }
} }
@@ -3156,7 +3241,7 @@ enum Arity {
impl From<&'static str> for Arity { impl From<&'static str> for Arity {
fn from(arity: &'static str) -> Self { fn from(arity: &'static str) -> Self {
usize::from_str_radix(&arity, 10) usize::from_str_radix(&arity, 10)
.map(|n| Arity::Static(n)) .map(Arity::Static)
.unwrap_or_else(|_| Arity::Ident(arity)) .unwrap_or_else(|_| Arity::Ident(arity))
} }
} }

View File

@@ -66,7 +66,7 @@ impl<'ast> Visit<'ast> for StaticStrVisitor {
if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() { if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() {
self.static_strs.insert(string.value()); self.static_strs.insert(string.value());
} }
} else if path.is_ident("read_heap_cell") { } else if path.is_ident("read_heap_cell") || path.is_ident("match_untyped_arena_ptr") {
if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() { if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() {
self.visit_expr(&m.expr); self.visit_expr(&m.expr);

View File

@@ -1,10 +1,10 @@
use crate::http::{HttpListener, HttpResponse};
use crate::machine::loader::LiveLoadState; use crate::machine::loader::LiveLoadState;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::raw_block::*; use crate::raw_block::*;
use crate::read::*; use crate::read::*;
use modular_bitfield::prelude::*;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use crate::parser::rug::{Integer, Rational}; use crate::parser::rug::{Integer, Rational};
@@ -21,7 +21,7 @@ macro_rules! arena_alloc {
($e:expr, $arena:expr) => {{ ($e:expr, $arena:expr) => {{
let result = $e; let result = $e;
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { $arena.alloc(result) } unsafe { ArenaAllocated::alloc($arena, result) }
}}; }};
} }
@@ -140,7 +140,8 @@ pub enum ArenaHeaderTag {
OutputFileStream = 0b10100, OutputFileStream = 0b10100,
NamedTcpStream = 0b011100, NamedTcpStream = 0b011100,
NamedTlsStream = 0b100000, NamedTlsStream = 0b100000,
NamedHttpClientStream = 0b100001, HttpReadStream = 0b100001,
HttpWriteStream = 0b100010,
ReadlineStream = 0b110000, ReadlineStream = 0b110000,
StaticStringStream = 0b110100, StaticStringStream = 0b110100,
ByteStream = 0b111000, ByteStream = 0b111000,
@@ -148,7 +149,13 @@ pub enum ArenaHeaderTag {
StandardErrorStream = 0b11000, StandardErrorStream = 0b11000,
NullStream = 0b111100, NullStream = 0b111100,
TcpListener = 0b1000000, TcpListener = 0b1000000,
HttpListener = 0b1000001,
HttpResponse = 0b1000010,
Dropped = 0b1000100, Dropped = 0b1000100,
IndexPtrDynamicUndefined = 0b1000101,
IndexPtrDynamicIndex = 0b1000110,
IndexPtrIndex = 0b1000111,
IndexPtrUndefined = 0b1001000,
} }
#[bitfield] #[bitfield]
@@ -234,7 +241,7 @@ impl<T: fmt::Display> fmt::Display for TypedArenaPtr<T> {
} }
} }
impl<T: ?Sized> TypedArenaPtr<T> { impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T> {
#[inline] #[inline]
pub const fn new(data: *mut T) -> Self { pub const fn new(data: *mut T) -> Self {
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) } unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
@@ -248,14 +255,14 @@ impl<T: ?Sized> TypedArenaPtr<T> {
#[inline] #[inline]
pub fn header_ptr(&self) -> *const ArenaHeader { pub fn header_ptr(&self) -> *const ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize; let mut ptr = self.as_ptr() as *const u8 as usize;
ptr -= mem::size_of::<*const ArenaHeader>(); ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
ptr as *const ArenaHeader ptr as *const ArenaHeader
} }
#[inline] #[inline]
fn header_ptr_mut(&mut self) -> *mut ArenaHeader { fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize; let mut ptr = self.as_ptr() as *const u8 as usize;
ptr -= mem::size_of::<*const ArenaHeader>(); ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
ptr as *mut ArenaHeader ptr as *mut ArenaHeader
} }
@@ -289,14 +296,35 @@ impl<T: ?Sized> TypedArenaPtr<T> {
} }
} }
pub trait ArenaAllocated { pub trait ArenaAllocated: Sized {
type PtrToAllocated; type PtrToAllocated;
fn tag() -> ArenaHeaderTag; fn tag() -> ArenaHeaderTag;
fn size(&self) -> usize; fn size(&self) -> usize;
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated;
where
Self: Sized; fn header_offset_from_payload() -> usize {
mem::size_of::<*const ArenaHeader>()
}
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
let size = value.size() + mem::size_of::<AllocSlab>();
let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab;
(*slab).next = arena.base;
(*slab).header = ArenaHeader::build_with(value.size() as u64, Self::tag());
let offset = (*slab).payload_offset();
let result = value.copy_to_arena(offset as *mut Self);
arena.base = slab;
result
}
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@@ -536,6 +564,93 @@ impl ArenaAllocated for TcpListener {
} }
} }
impl ArenaAllocated for HttpListener {
type PtrToAllocated = TypedArenaPtr<HttpListener>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpListener
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
impl ArenaAllocated for HttpResponse {
type PtrToAllocated = TypedArenaPtr<HttpResponse>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpResponse
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
}
impl ArenaAllocated for IndexPtr {
type PtrToAllocated = TypedArenaPtr<IndexPtr>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::IndexPtrUndefined
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe {
ptr::write(dst, self);
TypedArenaPtr::new(dst as *mut Self)
}
}
#[inline]
fn header_offset_from_payload() -> usize {
0
}
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
let size = mem::size_of::<AllocSlab>();
let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab;
(*slab).next = arena.base;
let result = value.copy_to_arena(mem::transmute::<_, *mut IndexPtr>(&(*slab).header));
arena.base = slab;
result
}
}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct AllocSlab { struct AllocSlab {
next: *mut AllocSlab, next: *mut AllocSlab,
@@ -556,25 +671,6 @@ impl Arena {
pub fn new() -> Self { pub fn new() -> Self {
Arena { base: ptr::null_mut(), f64_tbl: F64Table::new() } Arena { base: ptr::null_mut(), f64_tbl: F64Table::new() }
} }
pub unsafe fn alloc<T: ArenaAllocated>(&mut self, value: T) -> T::PtrToAllocated {
let size = value.size() + mem::size_of::<AllocSlab>();
let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab;
(*slab).next = self.base;
(*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag());
let offset = (*slab).payload_offset();
let result = value.copy_to_arena(offset as *mut T);
self.base = slab;
result
}
} }
unsafe fn drop_slab_in_place(value: &mut AllocSlab) { unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
@@ -599,9 +695,12 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
ArenaHeaderTag::NamedTlsStream => { ArenaHeaderTag::NamedTlsStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
} }
ArenaHeaderTag::NamedHttpClientStream => { ArenaHeaderTag::HttpReadStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedHttpClientStream>>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpReadStream>>>());
} }
ArenaHeaderTag::HttpWriteStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpWriteStream>>>());
}
ArenaHeaderTag::ReadlineStream => { ArenaHeaderTag::ReadlineStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
} }
@@ -622,13 +721,21 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
ArenaHeaderTag::TcpListener => { ArenaHeaderTag::TcpListener => {
ptr::drop_in_place(value.payload_offset::<TcpListener>()); ptr::drop_in_place(value.payload_offset::<TcpListener>());
} }
ArenaHeaderTag::HttpListener => {
ptr::drop_in_place(value.payload_offset::<HttpListener>());
}
ArenaHeaderTag::HttpResponse => {
ptr::drop_in_place(value.payload_offset::<HttpResponse>());
}
ArenaHeaderTag::StandardOutputStream => { ArenaHeaderTag::StandardOutputStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
} }
ArenaHeaderTag::StandardErrorStream => { ArenaHeaderTag::StandardErrorStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>());
} }
ArenaHeaderTag::NullStream => { ArenaHeaderTag::NullStream | ArenaHeaderTag::IndexPtrUndefined |
ArenaHeaderTag::IndexPtrDynamicUndefined | ArenaHeaderTag::IndexPtrDynamicIndex |
ArenaHeaderTag::IndexPtrIndex => {
} }
} }
} }
@@ -745,7 +852,8 @@ mod tests {
// integer // integer
let big_int: Integer = 2 * Integer::from(1u64 << 63); let big_int: Integer = 2 * Integer::from(1u64 << 63);
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, wam.machine_st.arena); let big_int_ptr: TypedArenaPtr<Integer> =
arena_alloc!(big_int, &mut wam.machine_st.arena);
assert!(!big_int_ptr.as_ptr().is_null()); assert!(!big_int_ptr.as_ptr().is_null());

View File

@@ -13,7 +13,6 @@ use crate::parser::rug::ops::PowAssign;
use crate::parser::rug::{Assign, Integer, Rational}; use crate::parser::rug::{Assign, Integer, Rational};
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use ordered_float::*; use ordered_float::*;
@@ -65,19 +64,22 @@ impl<'a> ArithInstructionIterator<'a> {
fn from(term: &'a Term) -> Result<Self, ArithmeticError> { fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
let state = match term { let state = match term {
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) { Term::Clause(cell, name, terms) => {
TermIterState::Clause(Level::Shallow, 0, cell, *name, terms)
}
/* match ClauseType::from(*name, terms.len()) {
ct @ ClauseType::Named(..) => { ct @ ClauseType::Named(..) => {
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
} }
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { ct @ ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default()); // let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
} }
_ => Err(ArithmeticError::NonEvaluableFunctor( _ => Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(*name), Literal::Atom(*name),
terms.len(), terms.len(),
)), )),
}?, }?,*/
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons), Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => { Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
return Err(ArithmeticError::NonEvaluableFunctor( return Err(ArithmeticError::NonEvaluableFunctor(
@@ -108,17 +110,17 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
while let Some(iter_state) = self.state_stack.pop() { while let Some(iter_state) = self.state_stack.pop() {
match iter_state { match iter_state {
TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)), TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
TermIterState::Clause(lvl, child_num, cell, ct, subterms) => { TermIterState::Clause(lvl, child_num, cell, name, subterms) => {
let arity = subterms.len(); let arity = subterms.len();
if child_num == arity { if child_num == arity {
return Some(Ok(ArithTermRef::Op(ct.name(), arity))); return Some(Ok(ArithTermRef::Op(name, arity)));
} else { } else {
self.state_stack.push(TermIterState::Clause( self.state_stack.push(TermIterState::Clause(
lvl, lvl,
child_num + 1, child_num + 1,
cell, cell,
ct, name,
subterms, subterms,
)); ));

View File

@@ -263,6 +263,27 @@ impl DebrayAllocator {
} }
} }
// if the final argument of the structure is a Literal::Index,
// decrement the arity of the PutStructure instruction by 1.
fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
match instr {
Instruction::PutStructure(_, ref mut arity, _) |
Instruction::GetStructure(_, ref mut arity, _) => {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
// it is acceptable if arity == 0 is the result of
// this decrement. call/N will have to read the index
// constant for '$call_inline' to succeed. to find it,
// it must know the heap location of the index.
// self.store must stop before reading the atom into a
// register.
*arity -= 1;
}
}
_ => {}
}
}
impl<'b> CodeGenerator<'b> { impl<'b> CodeGenerator<'b> {
pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self { pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self {
CodeGenerator { CodeGenerator {
@@ -369,9 +390,15 @@ impl<'b> CodeGenerator<'b> {
self.marker.mark_anon_var::<Target>(lvl, term_loc, &mut target); self.marker.mark_anon_var::<Target>(lvl, term_loc, &mut target);
} }
} }
TermRef::Clause(lvl, cell, ct, terms) => { TermRef::Clause(lvl, cell, name, terms) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target); self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push(Target::to_structure(ct.name(), terms.len(), cell.get())); target.push(Target::to_structure(name, terms.len(), cell.get()));
if let Some(instr) = target.last_mut() {
if let Some(term) = terms.last() {
trim_structure_by_last_arg(instr, term);
}
}
for subterm in terms { for subterm in terms {
self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target); self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target);
@@ -1039,10 +1066,7 @@ impl<'b> CodeGenerator<'b> {
let iter = query_term_post_order_iter(term); let iter = query_term_post_order_iter(term);
let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed); let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed);
if !query.is_empty() { code.extend(query.into_iter());
code.extend(query.into_iter());
}
self.add_conditional_call(code, term, num_perm_vars_left); self.add_conditional_call(code, term, num_perm_vars_left);
} }

View File

@@ -154,24 +154,21 @@ impl ClauseInfo for PredicateKey {
impl ClauseInfo for Term { impl ClauseInfo for Term {
fn name(&self) -> Option<Atom> { fn name(&self) -> Option<Atom> {
//, atom_tbl: &AtomTable) -> Option<StringBuffer> {
match self { match self {
Term::Clause(_, name, terms) => { Term::Clause(_, name, terms) => {
// let str_buf = StringBuffer::from(*name, atom_tbl);
match name.as_str() { match name {
// str_buf.as_str() { atom!(":-") => {
":-" => {
match terms.len() { match terms.len() {
1 => None, // a declaration. 1 => None, // a declaration.
2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)), 2 => terms[0].name(),
_ => Some(*name), _ => Some(*name),
} }
} }
_ => Some(*name), //str_buf), _ => Some(*name), //str_buf),
} }
} }
Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)), Term::Literal(_, Literal::Atom(name)) => Some(*name),
_ => None, _ => None,
} }
} }

View File

@@ -89,6 +89,17 @@ impl<'a> Drop for StackfulPreOrderHeapIter<'a> {
} }
} }
pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
fn focus(&self) -> usize;
}
impl<'a> FocusedHeapIter for StackfulPreOrderHeapIter<'a> {
#[inline]
fn focus(&self) -> usize {
self.h
}
}
impl<'a> StackfulPreOrderHeapIter<'a> { impl<'a> StackfulPreOrderHeapIter<'a> {
#[inline] #[inline]
fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self { fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
@@ -126,11 +137,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
None None
} }
#[inline]
pub fn focus(&self) -> usize {
self.h
}
#[inline] #[inline]
pub fn pop_stack(&mut self) -> Option<HeapCellValue> { pub fn pop_stack(&mut self) -> Option<HeapCellValue> {
while let Some(h) = self.stack.pop() { while let Some(h) = self.stack.pop() {
@@ -271,13 +277,14 @@ pub(crate) fn stackful_preorder_iter(
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct PostOrderIterator<Iter: Iterator<Item = HeapCellValue>> { pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
focus: usize,
base_iter: Iter, base_iter: Iter,
base_iter_valid: bool, base_iter_valid: bool,
parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node. parent_stack: Vec<(usize, HeapCellValue, usize)>, // number of children, parent node, focus.
} }
impl<Iter: Iterator<Item = HeapCellValue>> Deref for PostOrderIterator<Iter> { impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
type Target = Iter; type Target = Iter;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@@ -285,9 +292,10 @@ impl<Iter: Iterator<Item = HeapCellValue>> Deref for PostOrderIterator<Iter> {
} }
} }
impl<Iter: Iterator<Item = HeapCellValue>> PostOrderIterator<Iter> { impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
pub(crate) fn new(base_iter: Iter) -> Self { pub(crate) fn new(base_iter: Iter) -> Self {
PostOrderIterator { PostOrderIterator {
focus: 0,
base_iter, base_iter,
base_iter_valid: true, base_iter_valid: true,
parent_stack: vec![], parent_stack: vec![],
@@ -295,32 +303,36 @@ impl<Iter: Iterator<Item = HeapCellValue>> PostOrderIterator<Iter> {
} }
} }
impl<Iter: Iterator<Item = HeapCellValue>> Iterator for PostOrderIterator<Iter> { impl<Iter: FocusedHeapIter> Iterator for PostOrderIterator<Iter> {
type Item = HeapCellValue; type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
if let Some((child_count, node)) = self.parent_stack.pop() { if let Some((child_count, node, focus)) = self.parent_stack.pop() {
if child_count == 0 { if child_count == 0 {
self.focus = focus;
return Some(node); return Some(node);
} }
self.parent_stack.push((child_count - 1, node)); self.parent_stack.push((child_count - 1, node, focus));
} }
if self.base_iter_valid { if self.base_iter_valid {
if let Some(item) = self.base_iter.next() { if let Some(item) = self.base_iter.next() {
let focus = self.base_iter.focus();
read_heap_cell!(item, read_heap_cell!(item,
(HeapCellValueTag::Atom, (_name, arity)) => { (HeapCellValueTag::Atom, (_name, arity)) => {
self.parent_stack.push((arity, item)); self.parent_stack.push((arity, item, focus));
} }
(HeapCellValueTag::Lis) => { (HeapCellValueTag::Lis) => {
self.parent_stack.push((2, item)); self.parent_stack.push((2, item, focus));
} }
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
self.parent_stack.push((1, item)); self.parent_stack.push((1, item, focus));
} }
_ => { _ => {
self.focus = focus;
return Some(item); return Some(item);
} }
); );
@@ -338,12 +350,40 @@ impl<Iter: Iterator<Item = HeapCellValue>> Iterator for PostOrderIterator<Iter>
} }
} }
impl<Iter: FocusedHeapIter> FocusedHeapIter for PostOrderIterator<Iter> {
#[inline(always)]
fn focus(&self) -> usize {
self.focus
}
}
impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
/* return true if the term at heap offset idx_loc is a
* direct/inlined subterm of a structure at the focus of
* self.stack.last(). this function is used to determine, e.g.,
* ownership of inlined code indices.
*/
#[inline]
pub(crate) fn direct_subterm_of_str(&self, idx_loc: usize) -> bool {
if let Some((_child_count, item, focus)) = self.parent_stack.last() {
read_heap_cell!(item,
(HeapCellValueTag::Atom, (_name, arity)) => {
return focus + arity >= idx_loc && *focus < idx_loc;
}
_ => {}
);
}
false
}
}
pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator<StackfulPreOrderHeapIter<'a>>; pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator<StackfulPreOrderHeapIter<'a>>;
impl<'a> LeftistPostOrderHeapIter<'a> { impl<'a> LeftistPostOrderHeapIter<'a> {
#[inline] #[inline]
pub fn pop_stack(&mut self) { pub fn pop_stack(&mut self) {
if let Some((child_count, _)) = self.parent_stack.last() { if let Some((child_count, ..)) = self.parent_stack.last() {
for _ in 0 .. *child_count { for _ in 0 .. *child_count {
self.base_iter.pop_stack(); self.base_iter.pop_stack();
} }

View File

@@ -1,6 +1,5 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::instructions::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::rug::{Integer, Rational}; use crate::parser::rug::{Integer, Rational};
use crate::{ use crate::{
@@ -377,9 +376,9 @@ impl HCValueOutputter for PrinterOutputter {
} }
} }
#[inline] #[inline(always)]
fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool { fn is_numbered_var(name: Atom, arity: usize) -> bool {
arity == 1 && ct.name() == atom!("$VAR") arity == 1 && name == atom!("$VAR")
} }
#[inline] #[inline]
@@ -469,7 +468,6 @@ pub fn fmt_float(mut fl: f64) -> String {
pub struct HCPrinter<'a, Outputter> { pub struct HCPrinter<'a, Outputter> {
outputter: Outputter, outputter: Outputter,
iter: StackfulPreOrderHeapIter<'a>, iter: StackfulPreOrderHeapIter<'a>,
arena: &'a mut Arena,
op_dir: &'a OpDir, op_dir: &'a OpDir,
state_stack: Vec<TokenOrRedirect>, state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>, toplevel_spec: Option<DirectedOp>,
@@ -534,7 +532,6 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String>
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
pub fn new( pub fn new(
heap: &'a mut Heap, heap: &'a mut Heap,
arena: &'a mut Arena,
op_dir: &'a OpDir, op_dir: &'a OpDir,
output: Outputter, output: Outputter,
cell: HeapCellValue, cell: HeapCellValue,
@@ -542,7 +539,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
HCPrinter { HCPrinter {
outputter: output, outputter: output,
iter: stackful_preorder_iter(heap, cell), iter: stackful_preorder_iter(heap, cell),
arena,
op_dir, op_dir,
state_stack: vec![], state_stack: vec![],
toplevel_spec: None, toplevel_spec: None,
@@ -563,9 +559,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
requires_space(tail, atom) requires_space(tail, atom)
} }
fn enqueue_op(&mut self, mut max_depth: usize, ct: ClauseType, spec: OpDesc) { fn enqueue_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) {
let name = ct.name();
if is_postfix!(spec.get_spec()) { if is_postfix!(spec.get_spec()) {
if self.check_max_depth(&mut max_depth) { if self.check_max_depth(&mut max_depth) {
self.iter.pop_stack(); self.iter.pop_stack();
@@ -652,25 +646,30 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.iter.pop_stack(); self.iter.pop_stack();
} }
self.state_stack.push(TokenOrRedirect::Close); if arity > 0 {
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::Open);
}
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Atom(name));
return false; return false;
} }
self.state_stack.push(TokenOrRedirect::Close); if arity > 0 {
self.state_stack.push(TokenOrRedirect::Close);
for _ in 0..arity { for _ in 0..arity {
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
}
self.state_stack.pop();
self.state_stack.push(TokenOrRedirect::Open);
} }
self.state_stack.pop();
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Atom(name));
true true
@@ -767,17 +766,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
&mut self, &mut self,
max_depth: usize, max_depth: usize,
arity: usize, arity: usize,
ct: ClauseType, name: Atom,
op_desc: Option<OpDesc>, op_desc: Option<OpDesc>,
) -> bool { ) -> bool {
if self.numbervars && is_numbered_var(&ct, arity) { if self.numbervars && is_numbered_var(name, arity) {
if self.format_numbered_vars() { if self.format_numbered_vars() {
return true; return true;
} }
} }
let dot_atom = atom!("."); let dot_atom = atom!(".");
let name = ct.name();
if let Some(spec) = op_desc { if let Some(spec) = op_desc {
if dot_atom == name && is_infix!(spec.get_spec()) { if dot_atom == name && is_infix!(spec.get_spec()) {
@@ -788,7 +786,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
if !self.ignore_ops && spec.get_prec() > 0 { if !self.ignore_ops && spec.get_prec() > 0 {
self.enqueue_op(max_depth, ct, spec); self.enqueue_op(max_depth, name, spec);
return true; return true;
} }
} }
@@ -858,7 +856,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
None None
} }
var_opt => { var_opt => {
if is_cyclic && addr.is_compound() { if is_cyclic && addr.is_compound(self.iter.heap) {
// self-referential variables are marked "cyclic". // self-referential variables are marked "cyclic".
match var_opt { match var_opt {
Some(var) => { Some(var) => {
@@ -1333,9 +1331,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
} }
let ct = ClauseType::from(name, arity); if self.format_clause(max_depth, arity, name, Some(op_desc)) && add_brackets {
if self.format_clause(max_depth, arity, ct, Some(op_desc)) && add_brackets {
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
if let Some(ref op) = &op { if let Some(ref op) = &op {
@@ -1349,10 +1345,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
#[allow(dead_code)] #[allow(dead_code)]
fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) { fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() { let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() {
( (addr.ip(), addr.port())
addr.ip(),
Number::arena_from(addr.port() as usize, self.arena),
)
} else { } else {
let disconnected_atom = atom!("$disconnected_tcp_listener"); let disconnected_atom = atom!("$disconnected_tcp_listener");
self.state_stack self.state_stack
@@ -1371,7 +1364,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth, max_depth,
NumberFocus::Unfocused(port), NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))),
None, None,
)); ));
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
@@ -1382,6 +1375,31 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn print_index_ptr(&mut self, index_ptr: IndexPtr, max_depth: usize) {
if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
let atom = self.state_stack.pop().unwrap();
self.state_stack.pop();
self.state_stack.pop();
let offset = if index_ptr.is_undefined() || index_ptr.is_dynamic_undefined() {
TokenOrRedirect::Atom(atom!("undefined"))
} else {
let idx = index_ptr.p() as i64;
TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))),
None,
)
};
self.state_stack.push(offset);
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(atom);
}
}
fn print_stream(&mut self, stream: Stream, max_depth: usize) { fn print_stream(&mut self, stream: Stream, max_depth: usize) {
if let Some(alias) = stream.options().get_alias() { if let Some(alias) = stream.options().get_alias() {
self.print_atom(alias); self.print_atom(alias);
@@ -1439,8 +1457,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
); );
} else { } else {
push_space_if_amb!(self, name.as_str(), { push_space_if_amb!(self, name.as_str(), {
let ct = ClauseType::from(name, arity); self.format_clause(max_depth, arity, name, None);
self.format_clause(max_depth, arity, ct, None);
}); });
} }
} else if fetch_op_spec(name, arity, self.op_dir).is_some() { } else if fetch_op_spec(name, arity, self.op_dir).is_some() {
@@ -1485,8 +1502,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
); );
} else { } else {
push_space_if_amb!(self, name.as_str(), { push_space_if_amb!(self, name.as_str(), {
let ct = ClauseType::from(name, arity); self.format_clause(max_depth, arity, name, None);
self.format_clause(max_depth, arity, ct, None);
}); });
} }
} }
@@ -1531,10 +1547,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.print_stream(stream, max_depth); self.print_stream(stream, max_depth);
} }
(ArenaHeaderTag::OssifiedOpDir, _op_dir) => { (ArenaHeaderTag::OssifiedOpDir, _op_dir) => {
append_str!(self, "'$ossified_op_dir'"); self.print_atom(atom!("$ossified_op_dir"));
} }
(ArenaHeaderTag::Dropped, _value) => { (ArenaHeaderTag::Dropped, _value) => {
append_str!(self, "'$dropped_value'"); self.print_atom(atom!("$dropped_value"));
}
(ArenaHeaderTag::IndexPtr, index_ptr) => {
self.print_index_ptr(*index_ptr, max_depth);
} }
_ => { _ => {
} }
@@ -1631,7 +1650,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1659,7 +1677,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1682,7 +1699,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1694,7 +1710,6 @@ mod tests {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1726,7 +1741,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0), heap_loc_as_cell!(0),
@@ -1744,7 +1758,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0), heap_loc_as_cell!(0),
@@ -1760,7 +1773,6 @@ mod tests {
{ {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1791,7 +1803,6 @@ mod tests {
{ {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1813,7 +1824,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
pstr_loc_as_cell!(0) pstr_loc_as_cell!(0)
@@ -1840,7 +1850,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0), heap_loc_as_cell!(0),

25
src/http.rs Normal file
View File

@@ -0,0 +1,25 @@
use std::sync::Arc;
use std::convert::Infallible;
use hyper::{Response, Request, Body};
use tokio::sync::Mutex;
use tokio::sync::mpsc::{channel, Receiver, Sender};
pub struct HttpListener {
pub incoming: Receiver<HttpRequest>
}
#[derive(Debug)]
pub struct HttpRequest {
pub request: Request<Body>,
pub response: HttpResponse,
}
pub type HttpResponse = Sender<Response<Body>>;
pub async fn serve_req(req: Request<Body>, tx: Arc<Mutex<Sender<HttpRequest>>>) -> Result<Response<Body>, Infallible> {
let (response_tx, mut rx) = channel(1);
let http_request = HttpRequest { request: req, response: response_tx };
tx.lock().await.send(http_request).await.unwrap();
Ok(rx.recv().await.unwrap())
}

View File

@@ -1466,17 +1466,20 @@ impl<I: Indexer> CodeOffsets<I> {
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
) { ) {
match optimal_arg { match optimal_arg {
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Clause(_, name, ref terms) => { &Term::Clause(_, name, ref terms) => {
clause_index_info.opt_arg_index_key = clause_index_info.opt_arg_index_key =
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len()); OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
self.index_structure(name, terms.len(), index); self.index_structure(name, terms.len(), index);
} }
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Literal(_, constant) => { &Term::Literal(_, constant) => {
let overlapping_constants = self.index_constant(atom_tbl, constant, index); let overlapping_constants = self.index_constant(atom_tbl, constant, index);

View File

@@ -1,7 +1,6 @@
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::machine_indices::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use std::cell::Cell; use std::cell::Cell;
@@ -16,7 +15,7 @@ pub(crate) enum TermRef<'a> {
AnonVar(Level), AnonVar(Level),
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term), Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Literal(Level, &'a Cell<RegType>, &'a Literal), Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Term>), Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>), PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Atom), CompleteString(Level, &'a Cell<RegType>, Atom),
Var(Level, &'a Cell<VarReg>, Rc<String>), Var(Level, &'a Cell<VarReg>, Rc<String>),
@@ -40,7 +39,7 @@ impl<'a> TermRef<'a> {
pub(crate) enum TermIterState<'a> { pub(crate) enum TermIterState<'a> {
AnonVar(Level), AnonVar(Level),
Literal(Level, &'a Cell<RegType>, &'a Literal), Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Term>), Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>), InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
@@ -54,8 +53,7 @@ impl<'a> TermIterState<'a> {
match term { match term {
Term::AnonVar => TermIterState::AnonVar(lvl), Term::AnonVar => TermIterState::AnonVar(lvl),
Term::Clause(cell, name, subterms) => { Term::Clause(cell, name, subterms) => {
let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default()); TermIterState::Clause(lvl, 0, cell, *name, subterms)
TermIterState::Clause(lvl, 0, cell, ct, subterms)
} }
Term::Cons(cell, head, tail) => { Term::Cons(cell, head, tail) => {
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
@@ -105,7 +103,7 @@ impl<'a> QueryIterator<'a> {
Level::Root, Level::Root,
0, 0,
r, r,
ClauseType::from(*name, terms.len()), *name,
terms, terms,
), ),
Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()), Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
@@ -118,14 +116,14 @@ impl<'a> QueryIterator<'a> {
fn new(term: &'a QueryTerm) -> Self { fn new(term: &'a QueryTerm) -> Self {
match term { match term {
&QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => { &QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms); let state = TermIterState::Clause(Level::Root, 1, cell, atom!("$call"), terms);
QueryIterator { QueryIterator {
state_stack: vec![state], state_stack: vec![state],
} }
} }
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { &QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms); let state = TermIterState::Clause(Level::Root, 0, cell, ct.name(), terms);
QueryIterator { QueryIterator {
state_stack: vec![state], state_stack: vec![state],
} }
@@ -167,28 +165,25 @@ impl<'a> Iterator for QueryIterator<'a> {
TermIterState::AnonVar(lvl) => { TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl)); return Some(TermRef::AnonVar(lvl));
} }
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => { TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
if child_num == child_terms.len() { if child_num == child_terms.len() {
match ct { match name {
ClauseType::CallN(_) => { atom!("$call") if lvl == Level::Root => {
self.push_subterm(Level::Shallow, &child_terms[0]); self.push_subterm(Level::Shallow, &child_terms[0]);
} }
ClauseType::Named(..) => { _ => {
return match lvl { return match lvl {
Level::Root => None, Level::Root => None,
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)), lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
} }
} }
_ => {
return None;
}
}; };
} else { } else {
self.state_stack.push(TermIterState::Clause( self.state_stack.push(TermIterState::Clause(
lvl, lvl,
child_num + 1, child_num + 1,
cell, cell,
ct, name,
child_terms, child_terms,
)); ));
@@ -257,8 +252,7 @@ impl<'a> FactIterator<'a> {
vec![TermIterState::AnonVar(Level::Root)] vec![TermIterState::AnonVar(Level::Root)]
} }
Term::Clause(cell, name, terms) => { Term::Clause(cell, name, terms) => {
let ct = ClauseType::from(*name, terms.len()); vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
} }
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
Level::Root, Level::Root,
@@ -305,14 +299,14 @@ impl<'a> Iterator for FactIterator<'a> {
TermIterState::AnonVar(lvl) => { TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl)); return Some(TermRef::AnonVar(lvl));
} }
TermIterState::Clause(lvl, _, cell, ct, child_terms) => { TermIterState::Clause(lvl, _, cell, name, child_terms) => {
for child_term in child_terms { for child_term in child_terms {
self.push_subterm(lvl.child_level(), child_term); self.push_subterm(lvl.child_level(), child_term);
} }
match lvl { match lvl {
Level::Root if !self.iterable_root => continue, Level::Root if !self.iterable_root => continue,
_ => return Some(TermRef::Clause(lvl, cell, ct, child_terms)), _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
}; };
} }
TermIterState::InitialCons(lvl, cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head, tail) => {

View File

@@ -19,6 +19,7 @@ mod fixtures;
mod forms; mod forms;
mod heap_iter; mod heap_iter;
pub mod heap_print; pub mod heap_print;
mod http;
mod indexing; mod indexing;
#[macro_use] #[macro_use]
pub mod instructions { pub mod instructions {

View File

@@ -1,7 +1,5 @@
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, !/0, (',')/2, (->)/2, :- module(builtins, [(=)/2, (\=)/2, (\+)/1, !/0, (',')/2, (->)/2,
(;)/2, (=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (;)/2, (=..)/2, abolish/1, asserta/1, assertz/1,
(:)/6, (:)/7, (:)/8, (:)/9, (:)/10, (:)/11,
(:)/12, abolish/1, asserta/1, assertz/1,
at_end_of_stream/0, at_end_of_stream/1, at_end_of_stream/0, at_end_of_stream/1,
atom_chars/2, atom_codes/2, atom_concat/3, atom_chars/2, atom_codes/2, atom_concat/3,
atom_length/2, bagof/3, call/1, call/2, call/3, atom_length/2, bagof/3, call/1, call/2, call/3,
@@ -41,81 +39,26 @@ false :- '$fail'.
% Once Scryer is bootstrapped, each is replaced with a version that % Once Scryer is bootstrapped, each is replaced with a version that
% uses expand_goal to pass the expanded goal along to '$call'. % uses expand_goal to pass the expanded goal along to '$call'.
call(G) :- '$call'(G). call(_).
call(G, A) :- '$call'(G, A). call(_, _).
call(G, A, B) :- '$call'(G, A, B). call(_, _, _).
call(G, A, B, C) :- '$call'(G, A, B, C). call(_, _, _, _).
call(G, A, B, C, D) :- '$call'(G, A, B, C, D). call(_, _, _, _, _).
call(G, A, B, C, D, E) :- '$call'(G, A, B, C, D, E). call(_, _, _, _, _, _).
call(G, A, B, C, D, E, F) :- '$call'(G, A, B, C, D, E, F). call(_, _, _, _, _, _, _).
call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G). call(_, _, _, _, _, _, _, _).
call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H). call(_, _, _, _, _, _, _, _, _).
% dynamic module resolution.
Module : Predicate :- :- meta_predicate catch(0, ?, 0).
( atom(Module) -> '$module_call'(Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1) :-
( atom(Module) ->
'$module_call'(A1, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2) :-
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3) :-
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) :-
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
; throw(error(type_error(atom, Module), (:)/2))
).
% flags. % flags.
@@ -185,7 +128,7 @@ fail :- '$fail'.
:- meta_predicate \+(0). :- meta_predicate \+(0).
\+ G :- '$call'(G), !, false. \+ G :- call(G), !, false.
\+ _. \+ _.
@@ -195,7 +138,7 @@ _ \= _.
:- meta_predicate once(0). :- meta_predicate once(0).
once(G) :- '$call'(G), !. once(G) :- call(G), !.
repeat. repeat.
@@ -216,17 +159,17 @@ G1 -> G2 :- control_entry_point((G1 -> G2)).
staggered_if_then(G1, G2) :- staggered_if_then(G1, G2) :-
'$get_staggered_cp'(B), '$get_staggered_cp'(B),
'$call'(G1), call(G1),
'$set_cp'(B), '$set_cp'(B),
'$call'(G2). call(G2).
G1 ; G2 :- control_entry_point((G1 ; G2)). G1 ; G2 :- control_entry_point((G1 ; G2)).
:- non_counted_backtracking staggered_sc/2. :- non_counted_backtracking staggered_sc/2.
staggered_sc(G, _) :- '$call'(G). staggered_sc(G, _) :- call(G).
staggered_sc(_, G) :- '$call'(G). staggered_sc(_, G) :- call(G).
!. !.
@@ -257,7 +200,7 @@ control_entry_point_(G) :-
:- non_counted_backtracking cont_list_to_goal/2. :- non_counted_backtracking cont_list_to_goal/2.
cont_list_goal([Cont], Cont) :- !. cont_list_goal([Cont], Cont) :- !.
cont_list_goal(Conts, builtins:dispatch_call_list(Conts)). cont_list_goal(Conts, '$call'(builtins:dispatch_call_list(Conts))).
:- non_counted_backtracking module_qualified_cut/1. :- non_counted_backtracking module_qualified_cut/1.
@@ -289,7 +232,7 @@ dispatch_prep(Gs, B, [Cont|Conts]) :-
dispatch_prep(G2, B, IConts1), dispatch_prep(G2, B, IConts1),
cont_list_goal(IConts0, Cont0), cont_list_goal(IConts0, Cont0),
cont_list_goal(IConts1, Cont1), cont_list_goal(IConts1, Cont1),
Cont = builtins:staggered_sc(Cont0, Cont1), Cont = '$call'(builtins:staggered_sc(Cont0, Cont1)),
Conts = [] Conts = []
; functor(Gs, ->, 2) -> ; functor(Gs, ->, 2) ->
arg(1, Gs, G1), arg(1, Gs, G1),
@@ -298,10 +241,10 @@ dispatch_prep(Gs, B, [Cont|Conts]) :-
dispatch_prep(G2, B, IConts2), dispatch_prep(G2, B, IConts2),
cont_list_goal(IConts1, Cont1), cont_list_goal(IConts1, Cont1),
cont_list_goal(IConts2, Cont2), cont_list_goal(IConts2, Cont2),
Cont = builtins:staggered_if_then(Cont1, Cont2), Cont = '$call'(builtins:staggered_if_then(Cont1, Cont2)),
Conts = [] Conts = []
; ( Gs == ! ; module_qualified_cut(Gs) ) -> ; ( Gs == ! ; module_qualified_cut(Gs) ) ->
Cont = builtins:set_cp(B), Cont = '$call'(builtins:set_cp(B)),
Conts = [] Conts = []
; Cont = Gs, ; Cont = Gs,
Conts = [] Conts = []
@@ -318,56 +261,56 @@ dispatch_prep(Gs, B, [Cont|Conts]) :-
dispatch_call_list([]). dispatch_call_list([]).
dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :- dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :-
!, !,
'$call_with_inference_counting'('$call'(G1)), '$call_with_inference_counting'(call(G1)),
'$call_with_inference_counting'('$call'(G2)), '$call_with_inference_counting'(call(G2)),
'$call_with_inference_counting'('$call'(G3)), '$call_with_inference_counting'(call(G3)),
'$call_with_inference_counting'('$call'(G4)), '$call_with_inference_counting'(call(G4)),
'$call_with_inference_counting'('$call'(G5)), '$call_with_inference_counting'(call(G5)),
'$call_with_inference_counting'('$call'(G6)), '$call_with_inference_counting'(call(G6)),
'$call_with_inference_counting'('$call'(G7)), '$call_with_inference_counting'(call(G7)),
'$call_with_inference_counting'('$call'(G8)), '$call_with_inference_counting'(call(G8)),
dispatch_call_list(Gs). dispatch_call_list(Gs).
dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :- dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :-
!, !,
'$call_with_inference_counting'('$call'(G1)), '$call_with_inference_counting'(call(G1)),
'$call_with_inference_counting'('$call'(G2)), '$call_with_inference_counting'(call(G2)),
'$call_with_inference_counting'('$call'(G3)), '$call_with_inference_counting'(call(G3)),
'$call_with_inference_counting'('$call'(G4)), '$call_with_inference_counting'(call(G4)),
'$call_with_inference_counting'('$call'(G5)), '$call_with_inference_counting'(call(G5)),
'$call_with_inference_counting'('$call'(G6)), '$call_with_inference_counting'(call(G6)),
'$call_with_inference_counting'('$call'(G7)). '$call_with_inference_counting'(call(G7)).
dispatch_call_list([G1,G2,G3,G4,G5,G6]) :- dispatch_call_list([G1,G2,G3,G4,G5,G6]) :-
!, !,
'$call_with_inference_counting'('$call'(G1)), '$call_with_inference_counting'(call(G1)),
'$call_with_inference_counting'('$call'(G2)), '$call_with_inference_counting'(call(G2)),
'$call_with_inference_counting'('$call'(G3)), '$call_with_inference_counting'(call(G3)),
'$call_with_inference_counting'('$call'(G4)), '$call_with_inference_counting'(call(G4)),
'$call_with_inference_counting'('$call'(G5)), '$call_with_inference_counting'(call(G5)),
'$call_with_inference_counting'('$call'(G6)). '$call_with_inference_counting'(call(G6)).
dispatch_call_list([G1,G2,G3,G4,G5]) :- dispatch_call_list([G1,G2,G3,G4,G5]) :-
!, !,
'$call_with_inference_counting'('$call'(G1)), '$call_with_inference_counting'(call(G1)),
'$call_with_inference_counting'('$call'(G2)), '$call_with_inference_counting'(call(G2)),
'$call_with_inference_counting'('$call'(G3)), '$call_with_inference_counting'(call(G3)),
'$call_with_inference_counting'('$call'(G4)), '$call_with_inference_counting'(call(G4)),
'$call_with_inference_counting'('$call'(G5)). '$call_with_inference_counting'(call(G5)).
dispatch_call_list([G1,G2,G3,G4]) :- dispatch_call_list([G1,G2,G3,G4]) :-
!, !,
'$call_with_inference_counting'('$call'(G1)), '$call_with_inference_counting'(call(G1)),
'$call_with_inference_counting'('$call'(G2)), '$call_with_inference_counting'(call(G2)),
'$call_with_inference_counting'('$call'(G3)), '$call_with_inference_counting'(call(G3)),
'$call_with_inference_counting'('$call'(G4)). '$call_with_inference_counting'(call(G4)).
dispatch_call_list([G1,G2,G3]) :- dispatch_call_list([G1,G2,G3]) :-
!, !,
'$call_with_inference_counting'('$call'(G1)), '$call_with_inference_counting'(call(G1)),
'$call_with_inference_counting'('$call'(G2)), '$call_with_inference_counting'(call(G2)),
'$call_with_inference_counting'('$call'(G3)). '$call_with_inference_counting'(call(G3)).
dispatch_call_list([G1,G2]) :- dispatch_call_list([G1,G2]) :-
!, !,
'$call_with_inference_counting'('$call'(G1)), '$call_with_inference_counting'(call(G1)),
'$call_with_inference_counting'('$call'(G2)). '$call_with_inference_counting'(call(G2)).
dispatch_call_list([G1]) :- dispatch_call_list([G1]) :-
'$call_with_inference_counting'('$call'(G1)). '$call_with_inference_counting'(call(G1)).
% univ. % univ.
@@ -444,7 +387,7 @@ get_args([Arg|Args], Func, I0, N) :-
get_args(Args, Func, I1, N). get_args(Args, Func, I1, N).
:- meta_predicate parse_options_list(?, 0, ?, ?, ?). :- meta_predicate parse_options_list(?, 2, ?, ?, ?).
parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
'$skip_max_list'(_, _, Options, Tail), '$skip_max_list'(_, _, Options, Tail),
@@ -455,7 +398,10 @@ parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
; Tail \== [] -> ; Tail \== [] ->
throw(error(type_error(list, Options), Stub)) % 8.11.5.3e) throw(error(type_error(list, Options), Stub)) % 8.11.5.3e)
), ),
( lists:maplist(nonvar, Options), ( lists:maplist('$call'(nonvar), Options), % need '$call' because
% maplist isn't
% declared as a
% meta-predicate yet
catch(lists:maplist(Selector, Options, OptionPairs0), catch(lists:maplist(Selector, Options, OptionPairs0),
error(E, _), error(E, _),
builtins:throw(error(E, Stub))) -> builtins:throw(error(E, Stub))) ->
@@ -619,8 +565,6 @@ term_variables(Term, Vars) :-
% exceptions. % exceptions.
:- meta_predicate catch(0, ?, 0).
:- non_counted_backtracking catch/3. :- non_counted_backtracking catch/3.
catch(G,C,R) :- catch(G,C,R) :-
@@ -633,11 +577,12 @@ catch(G,C,R) :-
catch(G,C,R,Bb) :- catch(G,C,R,Bb) :-
'$install_new_block'(NBb), '$install_new_block'(NBb),
'$call_with_inference_counting'('$call'(G)), '$call_with_inference_counting'(call(G)),
end_block(Bb, NBb). end_block(Bb, NBb).
catch(G,C,R,Bb) :- catch(G,C,R,Bb) :-
'$reset_block'(Bb), '$reset_block'(Bb),
'$get_ball'(Ball), '$get_ball'(Ball),
'$push_ball_stack', % move ball to ball stack.
handle_ball(Ball, C, R). handle_ball(Ball, C, R).
@@ -654,9 +599,10 @@ end_block(Bb, NBb) :-
handle_ball(C, C, R) :- handle_ball(C, C, R) :-
!, !,
'$erase_ball', '$pop_ball_stack', % remove ball from ball stack.
'$call'(R). call(R).
handle_ball(_, _, _) :- handle_ball(_, _, _) :-
'$pop_from_ball_stack', % restore ball from ball stack.
'$unwind_stack'. '$unwind_stack'.
:- non_counted_backtracking throw/1. :- non_counted_backtracking throw/1.
@@ -671,7 +617,7 @@ throw(Ball) :-
:- non_counted_backtracking '$iterate_find_all'/4. :- non_counted_backtracking '$iterate_find_all'/4.
'$iterate_find_all'(Template, Goal, _, LhOffset) :- '$iterate_find_all'(Template, Goal, _, LhOffset) :-
'$call_with_inference_counting'('$call'(Goal)), '$call_with_inference_counting'(call(Goal)),
'$copy_to_lh'(LhOffset, Template), '$copy_to_lh'(LhOffset, Template),
'$fail'. '$fail'.
'$iterate_find_all'(_, _, Solutions, LhOffset) :- '$iterate_find_all'(_, _, Solutions, LhOffset) :-
@@ -684,6 +630,12 @@ truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
:- meta_predicate findall(?, 0, ?). :- meta_predicate findall(?, 0, ?).
:- non_counted_backtracking findall_cleanup/2.
findall_cleanup(LhLength, Error) :-
truncate_lh_to(LhLength),
throw(Error).
:- non_counted_backtracking findall/3. :- non_counted_backtracking findall/3.
findall(Template, Goal, Solutions) :- findall(Template, Goal, Solutions) :-
@@ -691,13 +643,13 @@ findall(Template, Goal, Solutions) :-
'$lh_length'(LhLength), '$lh_length'(LhLength),
catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength), catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength),
Error, Error,
( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ) builtins:findall_cleanup(LhLength, Error)
). ).
:- non_counted_backtracking '$iterate_find_all_diff'/5. :- non_counted_backtracking '$iterate_find_all_diff'/5.
'$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :- '$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
'$call_with_inference_counting'('$call'(Goal)), '$call_with_inference_counting'(call(Goal)),
'$copy_to_lh'(LhOffset, Template), '$copy_to_lh'(LhOffset, Template),
'$fail'. '$fail'.
'$iterate_find_all_diff'(_, _, Solutions0, Solutions1, LhOffset) :- '$iterate_find_all_diff'(_, _, Solutions0, Solutions1, LhOffset) :-
@@ -716,7 +668,7 @@ findall(Template, Goal, Solutions0, Solutions1) :-
catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0, catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0,
Solutions1, LhLength), Solutions1, LhLength),
Error, Error,
( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ) builtins:findall_cleanup(LhLength, Error)
). ).
:- non_counted_backtracking set_difference/3. :- non_counted_backtracking set_difference/3.
@@ -806,7 +758,8 @@ bagof(Template, Goal, Solution) :-
:- non_counted_backtracking iterate_variants_and_sort/3. :- non_counted_backtracking iterate_variants_and_sort/3.
iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :- iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
sort(Solution0, Solution), sort(Solution0, Solution1),
Solution1 = Solution,
( GroupSolutions == [] -> ! ( GroupSolutions == [] -> !
; true ; true
). ).
@@ -878,129 +831,35 @@ clause(H, B) :-
). ).
call_asserta(Head, Body, Name, Arity, Module) :- :- meta_predicate asserta(:).
'$clause_body_is_valid'(Body),
functor(_, Name, Arity),
'$asserta'(Head, Body, Name, Arity, Module).
module_asserta_clause(Head, Body, Module) :-
( var(Head) ->
throw(error(instantiation_error, asserta/1))
; callable(Head), functor(Head, Name, Arity) ->
( '$head_is_dynamic'(Module, Head) ->
call_asserta(Head, Body, Name, Arity, Module)
; '$no_such_predicate'(Module, Head) ->
call_asserta(Head, Body, Name, Arity, Module)
; throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1))
)
; throw(error(type_error(callable, Head), asserta/1))
).
asserta_clause(Head, Body) :-
( var(Head) ->
throw(error(instantiation_error, asserta/1))
; callable(Head), functor(Head, Name, Arity) ->
( Name == (:),
Arity =:= 2 ->
arg(1, Head, Module),
arg(2, Head, HeadAndBody),
( HeadAndBody = (F :- Body1) ->
true
; F = HeadAndBody,
Body1 = true
),
module_asserta_clause(F, Body1, Module)
; '$head_is_dynamic'(user, Head) ->
call_asserta(Head, Body, Name, Arity, user)
; '$no_such_predicate'(user, Head) ->
call_asserta(Head, Body, Name, Arity, user)
; throw(error(permission_error(modify, static_procedure, Name/Arity),
asserta/1))
)
; throw(error(type_error(callable, Head), asserta/1))
).
:- meta_predicate asserta(0).
asserta(Clause0) :- asserta(Clause0) :-
loader:strip_module(Clause0, Module, Clause), loader:strip_subst_module(Clause0, user, Module, Clause),
( var(Module) -> Module = user iso_ext:asserta(Module, Clause).
; true
),
( Clause \= (_ :- _) ->
Head = Clause,
Body = true,
module_asserta_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
module_asserta_clause(Head, Body, Module)
).
module_assertz_clause(Head, Body, Module) :- :- meta_predicate assertz(:).
( var(Head) ->
throw(error(instantiation_error, assertz/1))
; callable(Head), functor(Head, Name, Arity) ->
( '$head_is_dynamic'(Module, Head) ->
call_assertz(Head, Body, Name, Arity, Module)
; '$no_such_predicate'(Module, Head) ->
call_assertz(Head, Body, Name, Arity, Module)
; throw(error(permission_error(modify, static_procedure, Name/Arity),
assertz/1))
)
; throw(error(type_error(callable, Head), assertz/1))
).
call_assertz(Head, Body, Name, Arity, Module) :-
'$clause_body_is_valid'(Body),
functor(_, Name, Arity),
'$assertz'(Head, Body, Name, Arity, Module).
assertz_clause(Head, Body) :-
( var(Head) ->
throw(error(instantiation_error, assertz/1))
; callable(Head), functor(Head, Name, Arity) ->
( Name == (:),
Arity =:= 2 ->
arg(1, Head, Module),
arg(2, Head, HeadAndBody),
( HeadAndBody = (F :- Body1) ->
true
; F = HeadAndBody,
Body1 = true
),
module_assertz_clause(F, Body1, Module)
; '$head_is_dynamic'(user, Head) ->
call_assertz(Head, Body, Name, Arity, user)
; '$no_such_predicate'(user, Head) ->
call_assertz(Head, Body, Name, Arity, user)
; throw(error(permission_error(modify, static_procedure, Name/Arity),
assertz/1))
)
; throw(error(type_error(callable, Head), assertz/1))
).
:- meta_predicate assertz(0).
assertz(Clause0) :- assertz(Clause0) :-
loader:strip_module(Clause0, Module, Clause), loader:strip_subst_module(Clause0, user, Module, Clause),
( var(Module) -> Module = user iso_ext:assertz(Module, Clause).
; true
),
( Clause \= (_ :- _) ->
Head = Clause,
Body = true,
module_assertz_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
module_assertz_clause(Head, Body, Module)
).
:- meta_predicate retract(:).
retract(Clause0) :-
loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) ->
loader:strip_module(Clause, Module, Head),
( var(Module) -> Module = user
; true
),
Body = true,
retract_module_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
retract_module_clause(Head, Body, Module)
).
module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :- module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :-
functor(VarHead, Name, Arity), functor(VarHead, Name, Arity),
findall((VarHead :- VarBody), Module:'$clause'(VarHead, VarBody), Clauses1), findall((VarHead :- VarBody), Module:'$clause'(VarHead, VarBody), Clauses1),
@@ -1086,23 +945,7 @@ retract_clause(Head, Body) :-
). ).
:- meta_predicate retract(0). :- meta_predicate retractall(:).
retract(Clause0) :-
loader:strip_module(Clause0, Module, Clause),
( Clause \= (_ :- _) ->
loader:strip_module(Clause, Module, Head),
( var(Module) -> Module = user
; true
),
Body = true,
retract_module_clause(Head, Body, Module)
; Clause = (Head :- Body) ->
retract_module_clause(Head, Body, Module)
).
:- meta_predicate retractall(0).
retractall(Head) :- retractall(Head) :-
retract_clause(Head, _), retract_clause(Head, _),
@@ -1139,7 +982,7 @@ module_abolish(Pred, Module) :-
). ).
:- meta_predicate abolish(0). :- meta_predicate abolish(:).
abolish(Pred) :- abolish(Pred) :-
( var(Pred) -> ( var(Pred) ->
@@ -1208,7 +1051,6 @@ current_predicate(Pred) :-
can_be_op_priority(Priority) :- var(Priority). can_be_op_priority(Priority) :- var(Priority).
can_be_op_priority(Priority) :- op_priority(Priority). can_be_op_priority(Priority) :- op_priority(Priority).
can_be_op_specifier(Spec) :- var(Spec). can_be_op_specifier(Spec) :- var(Spec).
can_be_op_specifier(Spec) :- op_specifier(Spec). can_be_op_specifier(Spec) :- op_specifier(Spec).

View File

@@ -251,7 +251,7 @@ chars_base64(Cs, Bs, Options) :-
'$chars_base64'(Cs, Bs, Padding, Charset) '$chars_base64'(Cs, Bs, Padding, Charset)
; must_be(chars, Cs), ; must_be(chars, Cs),
( '$first_non_octet'(Cs, N) -> ( '$first_non_octet'(Cs, N) ->
domain_error(byte_char, N, chars_base64/3) domain_error(octet_character, N, chars_base64/3)
; '$chars_base64'(Cs, Bs, Padding, Charset) ; '$chars_base64'(Cs, Bs, Padding, Charset)
) )
). ).

View File

@@ -1122,6 +1122,8 @@ indomain(1).
% CountAnd = 1. % CountAnd = 1.
% == % ==
sat_count(Sat0, N) :- sat_count(Sat0, N) :-
catch((parse_sat(Sat0, Sat), catch((parse_sat(Sat0, Sat),
sat_bdd(Sat, BDD), sat_bdd(Sat, BDD),

View File

@@ -123,6 +123,8 @@
:- use_module(library(si)). :- use_module(library(si)).
:- use_module(library(freeze)). :- use_module(library(freeze)).
:- use_module(library(arithmetic)). :- use_module(library(arithmetic)).
:- use_module(library(debug)).
:- use_module(library(format)).
% :- use_module(library(types)). % :- use_module(library(types)).
@@ -194,6 +196,8 @@ type_error(Expectation, Term) :-
type_error(Expectation, Term, unknown(Term)-1). type_error(Expectation, Term, unknown(Term)-1).
:- meta_predicate(partition(1, ?, ?, ?)).
partition(Pred, Ls0, As, Bs) :- partition(Pred, Ls0, As, Bs) :-
include(Pred, Ls0, As), include(Pred, Ls0, As),
exclude(Pred, Ls0, Bs). exclude(Pred, Ls0, Bs).
@@ -214,6 +218,8 @@ partition_([X|Xs], Pred, Ls0, Es0, Gs0) :-
include/3 and exclude/3 include/3 and exclude/3
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- meta_predicate(include(1, ?, ?)).
include(Goal, Ls0, Ls) :- include(Goal, Ls0, Ls) :-
include_(Ls0, Goal, Ls). include_(Ls0, Goal, Ls).
@@ -226,6 +232,7 @@ include_([L|Ls0], Goal, Ls) :-
include_(Ls0, Goal, Rest). include_(Ls0, Goal, Rest).
:- meta_predicate(exclude(1, ?, ?)).
exclude(Goal, Ls0, Ls) :- exclude(Goal, Ls0, Ls) :-
exclude_(Ls0, Goal, Ls). exclude_(Ls0, Goal, Ls).
@@ -2236,8 +2243,8 @@ all_distinct(Ls) :-
fd_must_be_list(Ls, all_distinct(Ls)-1), fd_must_be_list(Ls, all_distinct(Ls)-1),
maplist(fd_variable, Ls), maplist(fd_variable, Ls),
make_propagator(pdistinct(Ls), Prop), make_propagator(pdistinct(Ls), Prop),
distinct_attach(Ls, Prop, []), new_queue(Q0),
trigger_once(Prop). phrase((distinct_attach(Ls, Prop, []),trigger_prop(Prop),do_queue), [Q0], _).
%% nvalue(?N, +Vars). %% nvalue(?N, +Vars).
% %
@@ -4045,12 +4052,13 @@ trigger_props(fd_props(Gs,Bs,Os)) -->
trigger_props_([]) --> []. trigger_props_([]) --> [].
trigger_props_([P|Ps]) --> trigger_prop(P), trigger_props_(Ps). trigger_props_([P|Ps]) --> trigger_prop(P), trigger_props_(Ps).
trigger_prop(_P) :- true. % TODO: What to do? trigger_prop(P) :- trigger_once(P).
trigger_prop(Propagator) --> trigger_prop(Propagator) -->
{ propagator_state(Propagator, State) }, { propagator_state(Propagator, State) },
( { State == dead } -> [] ( { State == dead } -> []
; { get_attr(State, clpz_aux, queued) } -> [] ; { get_attr(State, clpz_aux, queued) } -> []
; { bb_get('$clpz_current_propagator', C), C == State } -> []
; % passive ; % passive
%{ format("triggering: ~w\n", [Propagator]) }, %{ format("triggering: ~w\n", [Propagator]) },
{ put_attr(State, clpz_aux, queued) }, { put_attr(State, clpz_aux, queued) },
@@ -4143,12 +4151,13 @@ no_reactivation(pgcc_single(_,_)).
%no_reactivation(scalar_product(_,_,_,_)). %no_reactivation(scalar_product(_,_,_,_)).
activate_propagator(propagator(P,State)) --> activate_propagator(propagator(P,State)) -->
% { portray_clause(running(P)) },
( State == dead -> [] ( State == dead -> []
; { del_attr(State, clpz_aux) }, ; { del_attr(State, clpz_aux) },
( { no_reactivation(P) } -> ( { no_reactivation(P) } ->
%b_setval('$clpz_current_propagator', State), TODO { bb_b_put('$clpz_current_propagator', State) },
run_propagator(P, State) run_propagator(P, State),
%b_setval('$clpz_current_propagator', []) { bb_b_put('$clpz_current_propagator', []) }
; run_propagator(P, State) ; run_propagator(P, State)
) )
). ).
@@ -4194,7 +4203,8 @@ queue_get_arg_(Queue, Which, Element) :-
). ).
queue_enabled --> state(queue(_,_,_,Aux)), { \+ get_atts(Aux, +enabled(false)) }. queue_enabled --> state(queue(_,_,_,Aux)), { \+ get_atts(Aux, +enabled(false)) }.
disable_queue --> state(queue(_,_,_,Aux)), { put_atts(Aux, +enabled(false)) }.
enable_queue --> state(queue(_,_,_,Aux)), { put_atts(Aux, +enabled(true)) }.
portray_propagator(propagator(P,_), F) :- functor(P, F, _). portray_propagator(propagator(P,_), F) :- functor(P, F, _).
@@ -4389,14 +4399,14 @@ run_propagator(pdifferent(Left,Right,X,_), MState) -->
run_propagator(pexclude(Left,Right,X), MState). run_propagator(pexclude(Left,Right,X), MState).
run_propagator(pexclude(Left,Right,X), _) --> run_propagator(pexclude(Left,Right,X), _) -->
{ ( ground(X) -> ( ground(X) ->
disable_queue, disable_queue,
exclude_fire(Left, Right, X), exclude_fire(Left, Right, X),
enable_queue enable_queue
; true ; true
) }. ).
run_propagator(pdistinct(Ls), _MState) --> { distinct(Ls) }. run_propagator(pdistinct(Ls), _MState) --> distinct(Ls).
run_propagator(pnvalue(N, Vars), _MState) --> { propagate_nvalue(N, Vars) }. run_propagator(pnvalue(N, Vars), _MState) --> { propagate_nvalue(N, Vars) }.
@@ -4430,8 +4440,8 @@ run_propagator(pgcc(Vs, _, Pairs), _) --> { gcc_global(Vs, Pairs) }.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
run_propagator(pcircuit(Vs), _MState) --> run_propagator(pcircuit(Vs), _MState) -->
{ distinct(Vs), distinct(Vs),
propagate_circuit(Vs) }. { propagate_circuit(Vs) }.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5928,12 +5938,12 @@ max_factor(L1, U1, L2, U2, Max) :-
CSPs", AAAI-94, Seattle, WA, USA, pp 362--367, 1994 CSPs", AAAI-94, Seattle, WA, USA, pp 362--367, 1994
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
distinct_attach([], _, _). distinct_attach([], _, _) --> [].
distinct_attach([X|Xs], Prop, Right) :- distinct_attach([X|Xs], Prop, Right) -->
( var(X) -> ( var(X) ->
init_propagator(X, Prop), { init_propagator(X, Prop),
make_propagator(pexclude(Xs,Right,X), P1), make_propagator(pexclude(Xs,Right,X), P1),
init_propagator(X, P1), init_propagator(X, P1) },
trigger_prop(P1) trigger_prop(P1)
; exclude_fire(Xs, Right, X) ; exclude_fire(Xs, Right, X)
), ),
@@ -6102,59 +6112,26 @@ put_free(F) :- put_attr(F, free, true).
free_node(F) :- get_attr(F, free, true). free_node(F) :- get_attr(F, free, true).
del_vars_attr(Vars, Attr) :- maplist(del_attr(Attr), Vars).
%del_attr_(Attr, Var) :- del_attr(Var, Attr).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This needs to be spelt out.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
% del_attr_(edges, Var) :- del_attr(Var, edges).
% del_attr_(parent, Var) :- del_attr(Var, parent).
% del_attr_(g0_edges, Var) :- del_attr(Var, g0_edges).
% del_attr_(index, Var) :- del_attr(Var, index).
% del_attr_(visited, Var) :- del_attr(Var, visited).
del_all_attrs(Var) :-
( var(Var) ->
Atts = [clpz,
clpz_aux,
clpz_relation,
edges,
flow,
parent,
free,
g0_edges,
used,
lowlink,
value,
visited,
index,
in_stack,
clpz_gcc_vs,
clpz_gcc_num,
clpz_gcc_occurred],
maplist(remove_attr(Var), Atts)
; true
).
remove_attr(Var, Attr) :-
functor(Term, Attr, 1),
put_atts(Var, -Term).
:- meta_predicate with_local_attributes(?, 0, ?). :- meta_predicate with_local_attributes(?, 0, ?).
:- dynamic(nat_copy/1).
with_local_attributes(Vars, Goal, Result) :- with_local_attributes(Vars, Goal, Result) :-
catch((Goal, catch((Goal,
maplist(del_all_attrs, Vars), % Create a copy where all attributes are removed. Only
% reset all attributes, only the result matters % the result and its relation to Vars matters. We throw
throw(local_attributes(Result,Vars))), % an exception to undo all modifications to attributes
local_attributes(Result,Vars), % we made during propagation, and unify the variables
% in the thrown copy with Vars in order to get the
% intended variables in Result.
asserta(nat_copy(Vars-Result)),
retract(nat_copy(Copy)),
throw(local_attributes(Copy))),
local_attributes(Vars-Result),
true). true).
distinct(Vars) :- distinct(Vars) -->
with_local_attributes(Vars, { with_local_attributes(Vars,
( difference_arcs(Vars, FreeLeft, FreeRight0), ( difference_arcs(Vars, FreeLeft, FreeRight0),
length(FreeLeft, LFL), length(FreeLeft, LFL),
length(FreeRight0, LFR), length(FreeRight0, LFR),
@@ -6165,11 +6142,16 @@ distinct(Vars) :-
maplist(g_g0, FreeLeft), maplist(g_g0, FreeLeft),
scc(FreeLeft, g0_successors), scc(FreeLeft, g0_successors),
maplist(dfs_used, FreeRight), maplist(dfs_used, FreeRight),
phrase(distinct_goals(FreeLeft), Gs)), Gs), phrase(distinct_goals(FreeLeft), Gs)), Gs) },
disable_queue, disable_queue,
maplist(call, Gs), neq_nums(Gs),
enable_queue. enable_queue.
neq_nums([]) --> [].
neq_nums([neq_num(V,N)|VNs]) -->
% { portray_clause(neq_num(V, N)) },
neq_num(V, N), neq_nums(VNs).
distinct_goals([]) --> []. distinct_goals([]) --> [].
distinct_goals([V|Vs]) --> distinct_goals([V|Vs]) -->
{ get_attr(V, edges, Es) }, { get_attr(V, edges, Es) },
@@ -6184,7 +6166,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
get_attr(To, lowlink, L2), get_attr(To, lowlink, L2),
L1 =\= L2 } -> L1 =\= L2 } ->
{ get_attr(To, value, N) }, { get_attr(To, value, N) },
[clpz:neq_num(V, N)] [neq_num(V, N)]
; [] ; []
), ),
distinct_goals_(Es, V). distinct_goals_(Es, V).
@@ -6376,6 +6358,10 @@ exclude_fire(Left, Right, E) :-
all_neq(Left, E), all_neq(Left, E),
all_neq(Right, E). all_neq(Right, E).
exclude_fire(Left, Right, E) -->
all_neq(Left, E),
all_neq(Right, E).
list_contains([X|Xs], Y) :- list_contains([X|Xs], Y) :-
( X == Y -> true ( X == Y -> true
; list_contains(Xs, Y) ; list_contains(Xs, Y)
@@ -6937,6 +6923,11 @@ vs_key_min_others([V|Vs], Key, Min0, Min, Others) :-
) )
). ).
all_neq([], _) --> [].
all_neq([X|Xs], C) -->
neq_num(X, C),
all_neq(Xs, C).
all_neq([], _). all_neq([], _).
all_neq([X|Xs], C) :- all_neq([X|Xs], C) :-
neq_num(X, C), neq_num(X, C),
@@ -6968,8 +6959,8 @@ circuit(Vs) :-
( L =:= 1 -> true ( L =:= 1 -> true
; neq_index(Vs, 1), ; neq_index(Vs, 1),
make_propagator(pcircuit(Vs), Prop), make_propagator(pcircuit(Vs), Prop),
distinct_attach(Vs, Prop, []), new_queue(Q0),
trigger_once(Prop) phrase((distinct_attach(Vs, Prop, []),trigger_prop(Prop),do_queue), [Q0], _)
). ).
neq_index([], _). neq_index([], _).
@@ -7149,10 +7140,6 @@ contribution_at(T, Task, Offset-Bs, Contribution) :-
?(Contribution) #= B*C ?(Contribution) #= B*C
). ).
nth1(I, Es, E) :-
I0 is I-1,
nth0(I0, Es, E).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% disjoint2(+Rectangles) %% disjoint2(+Rectangles)

View File

@@ -65,8 +65,7 @@
hex_bytes(Hs, Bytes) :- hex_bytes(Hs, Bytes) :-
( ground(Hs) -> ( ground(Hs) ->
must_be(list, Hs), must_be(chars, Hs),
maplist(must_be(atom), Hs),
( phrase(hex_bytes(Hs), Bytes) -> ( phrase(hex_bytes(Hs), Bytes) ->
true true
; domain_error(hex_encoding, Hs, hex_bytes/2) ; domain_error(hex_encoding, Hs, hex_bytes/2)
@@ -104,10 +103,10 @@ must_be_bytes(Bytes, Context) :-
). ).
must_be_byte_chars(Chars, Context) :- must_be_octet_chars(Chars, Context) :-
must_be(chars, Chars), must_be(chars, Chars),
( '$first_non_octet'(Chars, F) -> ( '$first_non_octet'(Chars, F) ->
domain_error(byte_char, F, Context) domain_error(octet_character, F, Context)
; true ; true
). ).
@@ -611,7 +610,7 @@ encoding_chars(octet, Bs, Cs) :-
maplist(char_code, Cs, Bs) maplist(char_code, Cs, Bs)
; Bs = Cs ; Bs = Cs
), ),
must_be_byte_chars(Cs, crypto_encoding). must_be_octet_chars(Cs, crypto_encoding).
encoding_chars(utf8, Cs, Cs) :- encoding_chars(utf8, Cs, Cs) :-
must_be(chars, Cs). must_be(chars, Cs).
@@ -652,17 +651,17 @@ ed25519_new_keypair(Pair) :-
'$ed25519_new_keypair'(Pair). '$ed25519_new_keypair'(Pair).
ed25519_keypair_public_key(Pair, PublicKey) :- ed25519_keypair_public_key(Pair, PublicKey) :-
must_be_byte_chars(Pair, ed25519_keypair_public_key), must_be_octet_chars(Pair, ed25519_keypair_public_key),
'$ed25519_keypair_public_key'(Pair, PublicKey). '$ed25519_keypair_public_key'(Pair, PublicKey).
ed25519_sign(Key, Data0, Signature, Options) :- ed25519_sign(Key, Data0, Signature, Options) :-
must_be_byte_chars(Key, ed25519_sign), must_be_octet_chars(Key, ed25519_sign),
options_data_chars(Options, Data0, Data, Encoding), options_data_chars(Options, Data0, Data, Encoding),
'$ed25519_sign'(Key, Data, Encoding, Signature0), '$ed25519_sign'(Key, Data, Encoding, Signature0),
hex_bytes(Signature, Signature0). hex_bytes(Signature, Signature0).
ed25519_verify(Key, Data0, Signature0, Options) :- ed25519_verify(Key, Data0, Signature0, Options) :-
must_be_byte_chars(Key, ed25519_verify), must_be_octet_chars(Key, ed25519_verify),
options_data_chars(Options, Data0, Data, Encoding), options_data_chars(Options, Data0, Data, Encoding),
hex_bytes(Signature0, Signature), hex_bytes(Signature0, Signature),
'$ed25519_verify'(Key, Data, Encoding, Signature). '$ed25519_verify'(Key, Data, Encoding, Signature).
@@ -714,12 +713,17 @@ curve25519_scalar_mult(Scalar, Point, Result) :-
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result). '$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
bytes_integer(Bs, N) :- bytes_integer(Bs, N) :-
foldl(pow, Bs, 0-0, N-_). foldl(pow, Bs, t(0,0,N), t(N,_,_)).
pow(B, N0-I0, N-I) :- pow(B, t(N0,P0,I0), t(N,P,I)) :-
( integer(I0) ->
B #= I0 mod 256,
I #= I0 >> 8
; true
),
B in 0..255, B in 0..255,
N #= N0 + B*256^I0, N #= N0 + B*256^P0,
I #= I0 + 1. P #= P0 + 1.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Operations on Elliptic Curves Operations on Elliptic Curves
@@ -762,11 +766,15 @@ crypto_curve_scalar_mult(Curve, Scalar, point(X,Y), point(RX, RY)) :-
curve_name(Curve, Name), curve_name(Curve, Name),
curve_field_length(Curve, L0), curve_field_length(Curve, L0),
L #= 2*L0, % for hex encoding L #= 2*L0, % for hex encoding
phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), Hex), phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), PointHex),
hex_bytes(Hex, Bytes), hex_bytes(PointHex, PointBytes),
'$crypto_curve_scalar_mult'(Name, Scalar, Bytes, SX, SY), once(bytes_integer(ScalarBytes, Scalar)),
number_chars(RX, SX), '$crypto_curve_scalar_mult'(Name, ScalarBytes, PointBytes, [_|Us]),
number_chars(RY, SY). maplist(char_code, Us, Bs),
length(XBs, 32),
append(XBs, YBs, Bs),
maplist(reverse, [XBs,YBs], RBs),
maplist(bytes_integer, RBs, [RX,RY]).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- crypto_name_curve(secp256k1, Curve), ?- crypto_name_curve(secp256k1, Curve),
@@ -818,16 +826,6 @@ fitting_exponent(N, E0, E) :-
fitting_exponent(N, E1, E) fitting_exponent(N, E1, E)
). ).
crypto_name_curve(secp112r1,
curve(secp112r1,
0x00db7c2abf62e35e668076bead208b,
0x00db7c2abf62e35e668076bead2088,
0x659ef8ba043916eede8911702b22,
point(0x09487239995a5ee76b55f9c2f098,
0xa89ce5af8724c0a23e0e0ff77500),
0x00db7c2abf62e35e7628dfac6561c5,
14,
1)).
crypto_name_curve(secp256k1, crypto_name_curve(secp256k1,
curve(secp256k1, curve(secp256k1,
0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, 0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,

View File

@@ -12,16 +12,6 @@
:- use_module(library(lists), [append/3, member/2]). :- use_module(library(lists), [append/3, member/2]).
:- use_module(library(loader), [strip_module/3]). :- use_module(library(loader), [strip_module/3]).
load_context(GRBody, Module, GRBody0) :-
strip_module(GRBody, Module, GRBody0),
( nonvar(Module) ->
true
; prolog_load_context(module, Module) ->
true
; true
).
:- meta_predicate phrase(2, ?). :- meta_predicate phrase(2, ?).
:- meta_predicate phrase(2, ?, ?). :- meta_predicate phrase(2, ?, ?).
@@ -30,12 +20,14 @@ phrase(GRBody, S0) :-
phrase(GRBody, S0, []). phrase(GRBody, S0, []).
phrase(GRBody, S0, S) :- phrase(GRBody, S0, S) :-
load_context(GRBody, Module, GRBody0), strip_module(GRBody, M, GRBody1),
( var(GRBody0) -> ( var(GRBody) ->
instantiation_error(phrase/3) instantiation_error(phrase/3)
; dcg_body(GRBody0, S0, S, GRBody1, Module) -> ; nonvar(GRBody1),
call(GRBody1) dcg_constr(GRBody1),
; type_error(callable, GRBody0, phrase/3) dcg_body(GRBody1, S0, S, GRBody2) ->
call(M:GRBody2)
; call(M:GRBody1, S0, S)
). ).
@@ -48,25 +40,25 @@ module_call_qualified(M, Call, Call1) :-
% The same version of the below two dcg_rule clauses, but with module scoping. % The same version of the below two dcg_rule clauses, but with module scoping.
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :- dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S1, Goal1, _), dcg_body(GRBody, S0, S1, Goal1),
dcg_terminals(Terminals, S, S1, Goal2), dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ). Body = ( Goal1, Goal2 ).
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :- dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
NonTerminal \= ( _, _ ), NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S, Body, _). dcg_body(GRBody, S0, S, Body).
% This program uses append/3 as defined in the Prolog prologue. % This program uses append/3 as defined in the Prolog prologue.
% Expands a DCG rule into a Prolog rule, when no error condition applies. % Expands a DCG rule into a Prolog rule, when no error condition applies.
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :- dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S1, Goal1, _), dcg_body(GRBody, S0, S1, Goal1),
dcg_terminals(Terminals, S, S1, Goal2), dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ). Body = ( Goal1, Goal2 ).
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :- dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
NonTerminal \= ( _, _ ), NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S, Body, _). dcg_body(GRBody, S0, S, Body).
dcg_non_terminal(NonTerminal, S0, S, Goal) :- dcg_non_terminal(NonTerminal, S0, S, Goal) :-
NonTerminal =.. NonTerminalUniv, NonTerminal =.. NonTerminalUniv,
@@ -76,21 +68,21 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
dcg_terminals(Terminals, S0, S, S0 = List) :- dcg_terminals(Terminals, S0, S, S0 = List) :-
append(Terminals, S, List). append(Terminals, S, List).
dcg_body(Var, S0, S, Body, M) :- dcg_body(Var, S0, S, Body) :-
var(Var), var(Var),
module_call_qualified(M, Var, Var1), Body = phrase(Var, S0, S).
Body = phrase(Var1, S0, S). dcg_body(GRBody, S0, S, Body) :-
dcg_body(GRBody, S0, S, Body, M) :-
nonvar(GRBody), nonvar(GRBody),
dcg_constr(GRBody), dcg_constr(GRBody),
dcg_cbody(GRBody, S0, S, Body, M). dcg_cbody(GRBody, S0, S, Body).
dcg_body(NonTerminal, S0, S, Goal1, M) :- dcg_body(NonTerminal, S0, S, Goal1) :-
nonvar(NonTerminal), nonvar(NonTerminal),
\+ dcg_constr(NonTerminal), \+ dcg_constr(NonTerminal),
NonTerminal \= ( _ -> _ ), NonTerminal \= ( _ -> _ ),
NonTerminal \= ( \+ _ ), NonTerminal \= ( \+ _ ),
module_call_qualified(M, Goal, Goal1), loader:strip_module(NonTerminal, M, NonTerminal0),
dcg_non_terminal(NonTerminal, S0, S, Goal). dcg_non_terminal(NonTerminal0, S0, S, Goal0),
module_call_qualified(M, Goal0, Goal1).
% The following constructs in a grammar rule body % The following constructs in a grammar rule body
% are defined in the corresponding subclauses. % are defined in the corresponding subclauses.
@@ -108,42 +100,44 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
% The principal functor of the first argument indicates % The principal functor of the first argument indicates
% the construct to be expanded. % the construct to be expanded.
dcg_cbody([], S0, S, S0 = S, _M). dcg_cbody([], S0, S, S0 = S).
dcg_cbody([T|Ts], S0, S, Goal, _M) :- dcg_cbody([T|Ts], S0, S, Goal) :-
must_be(list, [T|Ts]), must_be(list, [T|Ts]),
dcg_terminals([T|Ts], S0, S, Goal). dcg_terminals([T|Ts], S0, S, Goal).
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :- dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
dcg_body(GRFirst, S0, S1, First, M), dcg_body(GRFirst, S0, S1, First),
dcg_body(GRSecond, S1, S, Second, M). dcg_body(GRSecond, S1, S, Second).
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :- dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
\+ subsumes_term(( _ -> _ ), GREither), \+ subsumes_term(( _ -> _ ), GREither),
dcg_body(GREither, S0, S, Either, M), dcg_body(GREither, S0, S, Either),
dcg_body(GROr, S0, S, Or, M). dcg_body(GROr, S0, S, Or).
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :- dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
subsumes_term(( _GRIf -> _GRThen ), GRCond), subsumes_term(( _GRIf -> _GRThen ), GRCond),
dcg_cbody(GRCond, S0, S, Cond, M), dcg_cbody(GRCond, S0, S, Cond),
dcg_body(GRElse, S0, S, Else, M). dcg_body(GRElse, S0, S, Else).
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :- dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
dcg_body(GREither, S0, S, Either, M), dcg_body(GREither, S0, S, Either),
dcg_body(GROr, S0, S, Or, M). dcg_body(GROr, S0, S, Or).
dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :- dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
module_call_qualified(M, Goal, Goal1). dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :- dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
module_call_qualified(M, Cont, Cont1). dcg_cbody(!, S0, S, ( !, S0 = S )).
dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :- dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
module_call_qualified(M, Body, Body1). dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
dcg_cbody(!, S0, S, ( !, S0 = S ), _M). dcg_body(GRIf, S0, S1, If),
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :- dcg_body(GRThen, S1, S, Then).
module_call_qualified(M, GRBody, GRBody1).
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :-
dcg_body(GRIf, S0, S1, If, M),
dcg_body(GRThen, S1, S, Then, M).
user:term_expansion(Term0, Term) :- user:term_expansion(Term0, Term) :-
nonvar(Term0), nonvar(Term0),
dcg_rule(Term0, Term). dcg_rule(Term0, Term).
% Describes a sequence % Describes a sequence
seq(Xs, Cs0,Cs) :-
var(Xs),
Cs0 == [],
!,
Xs = [],
Cs0 = Cs.
seq([]) --> []. seq([]) --> [].
seq([E|Es]) --> [E], seq(Es). seq([E|Es]) --> [E], seq(Es).
@@ -152,19 +146,23 @@ seqq([]) --> [].
seqq([Es|Ess]) --> seq(Es), seqq(Ess). seqq([Es|Ess]) --> seq(Es), seqq(Ess).
% Describes an arbitrary number of elements % Describes an arbitrary number of elements
...(Cs0,Cs) :-
Cs0 == [],
!,
Cs0 = Cs.
... --> [] | [_], ... . ... --> [] | [_], ... .
error_goal(error(E, must_be/2), error(E, must_be/2)). error_goal(error(E, must_be/2), error(E, must_be/2)).
error_goal(error(E, (=..)/2), error(E, (=..)/2)). error_goal(error(E, (=..)/2), error(E, (=..)/2)).
error_goal(E, _) :- throw(E). error_goal(E, _) :- throw(E).
user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :- user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :-
load_context(GRBody, M, GRBody0), loader:strip_module(GRBody, M, GRBody0),
nonvar(GRBody0), nonvar(GRBody0),
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M), catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1),
E, E,
dcgs:error_goal(E, GRBody1) dcgs:error_goal(E, GRBody1)
). ),
module_call_qualified(M, GRBody1, GRBody2).
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])). user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).

View File

@@ -10,6 +10,10 @@
type_error/3 type_error/3
]). ]).
:- meta_predicate check_(1, ?, ?).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
must_be(Type, Term) must_be(Type, Term)
@@ -31,6 +35,8 @@
- in_character - in_character
- integer - integer
- list - list
- octet_character
- octet_chars
- term - term
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -46,6 +52,11 @@ must_be_(var, Term) :-
; throw(error(uninstantiation_error(Term), must_be/2)) ; throw(error(uninstantiation_error(Term), must_be/2))
). ).
must_be_(integer, Term) :- check_(integer, integer, Term). must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(not_less_than_zero, N) :-
must_be(integer, N),
( N >= 0 -> true
; domain_error(not_less_than_zero, N, must_be/2)
).
must_be_(atom, Term) :- check_(atom, atom, Term). must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(character, T) :- check_(error:character, character, T). must_be_(character, T) :- check_(error:character, character, T).
must_be_(in_character, T) :- check_(error:in_character, in_character, T). must_be_(in_character, T) :- check_(error:in_character, in_character, T).
@@ -59,6 +70,17 @@ must_be_(chars, Ls) :-
true true
; all_characters(Ls) ; all_characters(Ls)
). ).
must_be_(octet_character, C) :-
must_be(character, C),
( octet_character(C) -> true
; domain_error(octet_character, C, must_be/2)
).
must_be_(octet_chars, Cs) :-
must_be(chars, Cs),
( '$first_non_octet'(Cs, C) ->
domain_error(octet_character, C, must_be/2)
; true
).
must_be_(list, Term) :- check_(error:ilist, list, Term). must_be_(list, Term) :- check_(error:ilist, list, Term).
must_be_(type, Term) :- check_(error:type, type, Term). must_be_(type, Term) :- check_(error:type, type, Term).
must_be_(boolean, Term) :- check_(error:boolean, boolean, Term). must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
@@ -90,6 +112,10 @@ character(C) :-
atom(C), atom(C),
atom_length(C, 1). atom_length(C, 1).
octet_character(C) :-
char_code(C, Code),
0 =< Code, Code =< 0xff.
in_character(C) :- in_character(C) :-
( character(C) ( character(C)
; C == end_of_file ; C == end_of_file
@@ -107,11 +133,14 @@ type(integer).
type(atom). type(atom).
type(character). type(character).
type(in_character). type(in_character).
type(octet_character).
type(octet_chars).
type(chars). type(chars).
type(list). type(list).
type(var). type(var).
type(boolean). type(boolean).
type(term). type(term).
type(not_less_than_zero).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
can_be(Type, Term) can_be(Type, Term)
@@ -135,6 +164,13 @@ can_be(Type, Term) :-
). ).
can_(integer, Term) :- integer(Term). can_(integer, Term) :- integer(Term).
can_(not_less_than_zero, N) :-
( integer(N) ->
( N >= 0 -> true
; domain_error(not_less_than_zero, N, can_be/2)
)
; type_error(integer, N, can_be/2)
).
can_(atom, Term) :- atom(Term). can_(atom, Term) :- atom(Term).
can_(character, T) :- character(T). can_(character, T) :- character(T).
can_(in_character, T) :- in_character(T). can_(in_character, T) :- in_character(T).
@@ -143,6 +179,17 @@ can_(chars, Ls) :-
; can_be(list, Ls), ; can_be(list, Ls),
can_be_chars(Ls) can_be_chars(Ls)
). ).
can_(octet_character, C) :-
( octet_character(C) -> true
; domain_error(octet_character, C, can_be/2)
).
can_(octet_chars, Cs) :-
can_be(chars, Cs),
( '$skip_max_list'(_, _, Cs, []), % temporarily turn Cs into a list
'$first_non_octet'(Cs, C) ->
domain_error(octet_character, C, can_be/2)
; true
).
can_(list, Term) :- list_or_partial_list(Term). can_(list, Term) :- list_or_partial_list(Term).
can_(boolean, Term) :- boolean(Term). can_(boolean, Term) :- boolean(Term).
can_(term, Term) :- can_(term, Term) :-

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written June 2020 by Markus Triska (triska@metalevel.at) Written 2020, 2022 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog. Part of Scryer Prolog.
Predicates for reasoning about files and directories. Predicates for reasoning about files and directories.
@@ -65,6 +65,7 @@
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(dcgs)).
directory_files(Directory, Files) :- directory_files(Directory, Files) :-
must_be(chars, Directory), must_be(chars, Directory),
@@ -73,7 +74,6 @@ directory_files(Directory, Files) :-
file_size(File, Size) :- file_size(File, Size) :-
file_must_exist(File, file_size/2), file_must_exist(File, file_size/2),
must_be(chars, File),
can_be(integer, Size), can_be(integer, Size),
'$file_size'(File, Size). '$file_size'(File, Size).
@@ -95,12 +95,10 @@ make_directory_path(Directory) :-
delete_file(File) :- delete_file(File) :-
file_must_exist(File, delete_file/1), file_must_exist(File, delete_file/1),
must_be(chars, File),
'$delete_file'(File). '$delete_file'(File).
rename_file(File, Renamed) :- rename_file(File, Renamed) :-
file_must_exist(File, rename_file/2), file_must_exist(File, rename_file/2),
must_be(chars, File),
must_be(chars, Renamed), must_be(chars, Renamed),
'$rename_file'(File, Renamed). '$rename_file'(File, Renamed).
@@ -201,19 +199,19 @@ path_segments(Path, Segments) :-
( var(Path) -> ( var(Path) ->
must_be(list, Segments), must_be(list, Segments),
maplist(must_be(chars), Segments), maplist(must_be(chars), Segments),
append_with_separator(Segments, Sep, Path) phrase(append_with_separator(Segments, Sep), Path)
; must_be(chars, Path), ; must_be(chars, Path),
path_to_segments(Path, Sep, Segments) path_to_segments(Path, Sep, Segments)
). ).
append_with_separator([], _, []). append_with_separator([], _) --> [].
append_with_separator([Segment|Segments], Sep, Path) :- append_with_separator([Segment|Segments], Sep) -->
append_with_separator_(Segments, Segment, Sep, Path). append_with_separator_(Segments, Segment, Sep).
append_with_separator_([], Segment, _, Segment). append_with_separator_([], Segment, _) --> seq(Segment).
append_with_separator_([Segment|Segments], Prev, Sep, Path) :- append_with_separator_([Segment|Segments], Prev, Sep) -->
append(Prev, [Sep|Rest], Path), seq(Prev), [Sep],
append_with_separator_(Segments, Segment, Sep, Rest). append_with_separator_(Segments, Segment, Sep).
path_to_segments(Path, Sep, Segments) :- path_to_segments(Path, Sep, Segments) :-
( append(Front, [Sep|Ps], Path) -> ( append(Front, [Sep|Ps], Path) ->

View File

@@ -3,7 +3,7 @@
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- meta_predicate freeze(?, 0). :- meta_predicate freeze(-, 0).
:- attribute frozen/1. :- attribute frozen/1.

View File

@@ -1,11 +1,11 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written in December 2020 by Adrián Arroyo (adrian.arroyocalle@gmail.com) Written in December 2020 by Adrián Arroyo (adrian.arroyocalle@gmail.com)
Updated in March 2022 by Adrián Arroyo to use the Hyper backend
Part of Scryer Prolog Part of Scryer Prolog
This library provides an starting point to build HTTP server based applications. This library provides an starting point to build HTTP server based applications.
It currently implements a subset of HTTP/1.0. It is recommended to put a reverse It is based on Hyper, which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However,
proxy like nginx in front of this server to have access to more advanced features some advanced features that Hyper provides are still not accesible.
(gzip compression, HTTPS, ...)
Usage Usage
========== ==========
@@ -41,37 +41,36 @@
Some things that are still missing: Some things that are still missing:
- Read forms in multipart format - Read forms in multipart format
- HTTP Basic Auth - HTTP Basic Auth
- Keep-Alive support
- Session handling via cookies - Session handling via cookies
- HTML Templating - HTML Templating
I place this code in the public domain. Use it in any way you want. I place this code in the public domain. Use it in any way you want.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(http_server, [ :- module(http_server, [
http_listen/2, http_listen/2,
http_headers/2, http_headers/2,
http_status_code/2, http_status_code/2,
http_body/2, http_body/2,
http_redirect/2, http_redirect/2,
http_query/3, http_query/3
url_decode//1
]). ]).
:- meta_predicate http_listen(?, 2). :- meta_predicate http_listen(?, :).
:- use_module(library(sockets)).
:- use_module(library(dcgs)).
:- use_module(library(format)).
:- use_module(library(error)).
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(lists)).
:- use_module(library(iso_ext)).
:- use_module(library(time)).
:- use_module(library(crypto)). :- use_module(library(crypto)).
:- use_module(library(error)).
:- use_module(library(format)).
:- use_module(library(iso_ext)).
:- use_module(library(lists)).
:- use_module(library(pio)).
:- use_module(library(time)).
% Module prefix workaround with meta_predicate
http_listen(Port, Module:Handlers0) :- http_listen(Port, Module:Handlers0) :-
must_be(integer, Port),
must_be(list, Handlers0),
maplist(module_qualification(Module), Handlers0, Handlers), maplist(module_qualification(Module), Handlers0, Handlers),
http_listen_(Port, Handlers). http_listen_(Port, Handlers).
@@ -79,49 +78,84 @@ module_qualification(M, H0, H) :-
H0 =.. [Method, Path, Goal], H0 =.. [Method, Path, Goal],
H =.. [Method, Path, M:Goal]. H =.. [Method, Path, M:Goal].
% Server initialization
http_listen_(Port, Handlers) :- http_listen_(Port, Handlers) :-
must_be(integer, Port), phrase(format_("0.0.0.0:~d", [Port]), Addr),
must_be(list, Handlers), '$http_listen'(Addr, HttpListener),!,
once(socket_server_open(Port, Socket)), format("Listening at ~s\n", [Addr]),
format("Listening at port ~d\n", [Port]), http_loop(HttpListener, Handlers).
accept_loop(Socket, Handlers).
% Server loop http_loop(HttpListener, Handlers) :-
accept_loop(Socket, Handlers) :- '$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle),
setup_call_cleanup(socket_server_accept(Socket, _Client, Stream, [type(binary)]), current_time(Time),
( phrase(format_time("%Y-%m-%d (%H:%M:%S)", Time), TimeString),
read_header_lines(Stream, Lines), format("~s ~w ~s\n", [TimeString, RequestMethod, RequestPath]),
[Request|Headers] = Lines, maplist(map_header_kv, RequestHeaders, RequestHeadersKV),
( phrase(parse_queries(RequestQueries), RequestQuery),
(phrase(parse_request(_Version, Method, Path, Queries), Request), maplist(map_parse_header, Headers, HeadersKV)) -> ( (
( match_handler(Handlers, RequestMethod, RequestPath, Handler) ->
member("content-length"-ContentLength, HeadersKV) -> (
(number_chars(ContentLengthN, ContentLength), get_bytes(Stream, ContentLengthN, Body)) HttpRequest = http_request(RequestHeadersKV, stream(RequestStream), RequestQueries),
;true HttpResponse = http_response(_, _, _),
), (call(Handler, HttpRequest, HttpResponse) ->
current_time(Time), send_response(ResponseHandle, HttpResponse)
phrase(format_time("%Y-%m-%d (%H:%M:%S)", Time), TimeString), ; (
format("~s ~w ~s\n", [TimeString, Method, Path]), '$http_answer'(ResponseHandle, 500, [], ResponseStream),
( call_cleanup(format(ResponseStream, "Internal Server Error", []), close(ResponseStream)))
match_handler(Handlers, Method, Path, Handler) -> )
( )
HttpRequest = http_request(HeadersKV, binary(Body), Queries), ; (
HttpResponse = http_response(_, _, _), '$http_answer'(ResponseHandle, 404, [], ResponseStream),
(call(Handler, HttpRequest, HttpResponse) -> call_cleanup(format(ResponseStream, "Not Found"), close(ResponseStream)))
send_response(Stream, HttpResponse) ),
; format(Stream, "HTTP/1.0 500 Internal Server Error\r\n\r\n", []) http_loop(HttpListener, Handlers).
)
) send_response(ResponseHandle, http_response(StatusCode0, text(ResponseText), ResponseHeaders0)) :-
; format(Stream, "HTTP/1.0 404 Not Found\r\n\r\n", []) default(StatusCode0, 200, StatusCode),
) maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
);( '$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
format(Stream, "HTTP/1.0 400 Bad Request\r\n\r\n", []) % bad format call_cleanup(
) format(ResponseStream, "~s", [ResponseText]),
), close(ResponseStream)
! % Remove ).
), close(Stream)),
accept_loop(Socket, Handlers). send_response(ResponseHandle, http_response(StatusCode0, bytes(ResponseBytes), ResponseHeaders0)) :-
default(StatusCode0, 200, StatusCode),
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
call_cleanup(
format(ResponseStream, "~s", [ResponseBytes]),
close(ResponseStream)
).
send_response(ResponseHandle, http_response(StatusCode0, file(Filename), ResponseHeaders0)) :-
default(StatusCode0, 200, StatusCode),
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
call_cleanup(
setup_call_cleanup(
open(Filename, read, FileStream, [type(binary)]),
(
get_n_chars(FileStream, _, FileCs),
format(ResponseStream, "~s", [FileCs])
),
close(FileStream)
),
close(ResponseStream)
).
default(Var, Default, Out) :-
(var(Var) -> Out = Default
; Var = Out
).
map_header_kv(T, K-V) :-
T =.. [K0, V],
atom_chars(K0, K).
map_header_kv_2(T, K-V) :-
atom_chars(K0, K),
T =.. [K0, V].
match_handler(Handlers, Method, "/", Handler) :- match_handler(Handlers, Method, "/", Handler) :-
member(H, Handlers), member(H, Handlers),
@@ -139,27 +173,6 @@ match_handler(Handlers, Method, Path, Handler) :-
var(Var), var(Var),
Var = Path. Var = Path.
% Helper and recommended predicates
http_headers(http_request(Headers, _, _), Headers).
http_headers(http_response(_, _, Headers), Headers).
http_body(http_request(_, binary(ByteBody), _), text(TextBody)) :- chars_utf8bytes(TextBody, ByteBody).
http_body(http_request(Headers, binary(ByteBody), _), form(FormBody)) :-
member("content-type"-"application/x-www-form-urlencoded", Headers),
chars_utf8bytes(TextBody, ByteBody),
phrase(parse_queries(FormBody), TextBody).
http_body(http_request(_, Body, _), Body).
http_body(http_response(_, Body, _), Body).
http_status_code(http_response(StatusCode, _, _), StatusCode).
http_redirect(http_response(307, text("Moved Temporarily"), ["Location"-Uri]), Uri).
http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries).
% Route matching
path(Pattern) --> path(Pattern) -->
{ {
Pattern =.. Parts, Pattern =.. Parts,
@@ -183,76 +196,31 @@ path(Pattern) -->
path([]) --> []. path([]) --> [].
% Send responses string_without(Not, [Char|String]) -->
send_response(Stream, http_response(StatusCode0, file(Filename), Headers)) :- [Char],
default(StatusCode0, 200, StatusCode), {
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]), \+ member(Char, Not)
overwrite_header("connection"-"Close", Headers, Headers0), },
write_headers(Stream, Headers0), string_without(Not, String).
format(Stream, "\r\n", []),
setup_call_cleanup(
open(Filename, read, FileStream, [type(binary)]),
pipe_bytes(FileStream, Stream),
close(FileStream)
).
send_response(Stream, http_response(StatusCode0, text(TextResponse), Headers)) :- string_without(_, []) -->
default(StatusCode0, 200, StatusCode), [].
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
overwrite_header("content-type"-"text/plain", Headers, Headers0),
overwrite_header("connection"-"Close", Headers0, Headers1),
write_headers(Stream, Headers1),
format(Stream, "\r\n~s", [TextResponse]).
send_response(Stream, http_response(StatusCode0, binary(BinaryResponse), Headers)) :- http_headers(http_request(Headers, _, _), Headers).
default(StatusCode0, 200, StatusCode), http_headers(http_response(_, _, Headers), Headers).
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
overwrite_header("connection"-"Close", Headers, Headers0),
write_headers(Stream, Headers0),
format(Stream, "\r\n", []),
put_bytes(Stream, BinaryResponse).
default(Var, Default, Out) :- http_body(http_request(_, stream(StreamBody), _), bytes(BytesBody)) :- get_n_chars(StreamBody, _, BytesBody).
(var(Var) -> Out = Default http_body(http_request(_, stream(StreamBody), _), text(TextBody)) :- get_n_chars(StreamBody, _, TextBody).
; Var = Out http_body(http_request(Headers, stream(StreamBody), _), form(FormBody)) :-
). member("content-type"-"application/x-www-form-urlencoded", Headers),
get_n_chars(StreamBody, _, TextBody),
phrase(parse_queries(FormBody), TextBody).
http_body(http_request(_, Body, _), Body).
http_body(http_response(_, Body, _), Body).
header([]) --> []. http_status_code(http_response(StatusCode, _, _), StatusCode).
header([Key-Value|Headers]) --> http_redirect(http_response(307, text("Moved Temporarily"), ["Location"-Uri]), Uri).
format_("~s: ~s\r\n", [Key, Value]), http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries).
header(Headers).
write_headers(Stream, Headers) :-
phrase(header(Headers), Cs),
format(Stream, "~s", [Cs]).
overwrite_header(Key-Value, [], [Key-Value]).
overwrite_header(Key-Value, [Header|Headers], [Header|HeadersOut]) :-
Header = Key0-_,
Key0 \= Key,
overwrite_header(Key-Value, Headers, HeadersOut).
overwrite_header(Key-Value, [Header|Headers], [NewHeader|Headers]) :-
Header = Key-_,
NewHeader = Key-Value.
parse_request(http_version(Major, Minor), Method, Path, Queries) -->
method(Method),
" ",
parse_path(Path, Queries),
" ",
"HTTP/",
natural(Major),
".",
natural(Minor),
"\r\n".
parse_path(Path, Queries) -->
string_without("?", Path),
"?",
parse_queries(Queries).
parse_path(Path, []) -->
string_without(" ", Path).
parse_queries([Key-Value|Queries]) --> parse_queries([Key-Value|Queries]) -->
string_without("=", Key0), string_without("=", Key0),
@@ -278,94 +246,9 @@ parse_queries([Key-Value]) -->
phrase(url_decode(Value), Value0) phrase(url_decode(Value), Value0)
}. }.
map_parse_header(Header, HeaderKV) :- parse_queries([]) -->
phrase(parse_header(HeaderKV), Header).
parse_header(Key-Value) -->
string_without(":", Key0),
{
chars_lower(Key0, Key)
},
": ",
string_without("\r", Value),
"\r\n".
method(options) --> "OPTIONS".
method(get) --> "GET".
method(head) --> "HEAD".
method(post) --> "POST".
method(put) --> "PUT".
method(delete) --> "DELETE".
string_without(Not, [Char|String]) -->
[Char],
{
\+ member(Char, Not)
},
string_without(Not, String).
string_without(_, []) -->
[]. [].
natural(Nat) -->
natural_(NatChars),
{
number_chars(Nat, NatChars)
}.
natural_([Nat|Nats]) -->
[Nat],
{
char_type(Nat, decimal_digit)
},
natural_(Nats).
natural_([]) -->
[].
read_header_lines(Stream, Hs) :-
read_line_to_chars(Stream, Cs, []),
( Cs == "" -> Hs = []
; Cs == "\r\n" -> Hs = []
; Hs = [Cs|Rest],
read_header_lines(Stream, Rest)
).
get_bytes(Stream, Length, Res) :- get_bytes(Stream, Length, [], Res).
get_bytes(Stream, Length, Acc, Res) :-
(Length > 0 -> (
get_byte(Stream, B),
B =\= -1,
get_bytes(Stream, Length - 1, [B|Acc], Res)
); reverse(Acc, Res)).
put_bytes(_, []).
put_bytes(Stream, [Byte|Bytes]) :-
put_byte(Stream, Byte),
put_bytes(Stream, Bytes).
pipe_bytes(StreamIn, StreamOut) :-
get_byte(StreamIn, Byte),
(
Byte =\= -1 ->
(
put_byte(StreamOut, Byte),
pipe_bytes(StreamIn, StreamOut)
)
; true).
% WARNING: This only works for ASCII chars. This code can be modified to support
% Latin1 characters also but a completely different approach is needed for other
% languages. Since HTTP internals are ASCII, this is fine for this usecase.
chars_lower(Chars, Lower) :-
maplist(char_lower, Chars, Lower).
char_lower(Char, Lower) :-
char_code(Char, Code),
((Code >= 65,Code =< 90) ->
LowerCode is Code + 32,
char_code(Lower, LowerCode)
; Char = Lower).
% Decodes a UTF-8 URL Encoded string: RFC-1738 % Decodes a UTF-8 URL Encoded string: RFC-1738
url_decode([Char|Chars]) --> url_decode([Char|Chars]) -->
[Char], [Char],

View File

@@ -1,8 +1,3 @@
%% for builtins that are not part of the ISO standard.
%% must be loaded at the REPL with
%% ?- use_module(library(iso_ext)).
:- module(iso_ext, [bb_b_put/2, :- module(iso_ext, [bb_b_put/2,
bb_get/2, bb_get/2,
bb_put/2, bb_put/2,
@@ -14,8 +9,9 @@
partial_string_tail/2, partial_string_tail/2,
setup_call_cleanup/3, setup_call_cleanup/3,
call_nth/2, call_nth/2,
% variant/2, copy_term_nat/2,
copy_term_nat/2]). asserta/2,
assertz/2]).
:- use_module(library(error), [can_be/2, :- use_module(library(error), [can_be/2,
domain_error/3, domain_error/3,
@@ -64,7 +60,7 @@ call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
setup_call_cleanup(S, G, C) :- setup_call_cleanup(S, G, C) :-
'$get_b_value'(B), '$get_b_value'(B),
'$call_with_inference_counting'('$call'(S)), '$call_with_inference_counting'(call(S)),
'$set_cp_by_default'(B), '$set_cp_by_default'(B),
'$get_current_block'(Bb), '$get_current_block'(Bb),
( C = _:CC, ( C = _:CC,
@@ -80,20 +76,20 @@ setup_call_cleanup(S, G, C) :-
scc_helper(C, G, Bb) :- scc_helper(C, G, Bb) :-
'$get_cp'(Cp), '$get_cp'(Cp),
'$install_scc_cleaner'(C, NBb), '$install_scc_cleaner'(C, NBb),
'$call_with_inference_counting'('$call'(G)), '$call_with_inference_counting'(call(G)),
( '$check_cp'(Cp) -> ( '$check_cp'(Cp) ->
'$reset_block'(Bb), '$reset_block'(Bb),
run_cleaners_without_handling(Cp) run_cleaners_without_handling(Cp)
; true ; true
; '$reset_block'(NBb), ; '$reset_block'(NBb),
'$fail' '$fail'
). ).
scc_helper(_, _, Bb) :- scc_helper(_, _, Bb) :-
'$reset_block'(Bb), '$reset_block'(Bb),
'$get_ball'(Ball), '$push_ball_stack',
'$erase_ball',
run_cleaners_with_handling, run_cleaners_with_handling,
throw(Ball). '$pop_from_ball_stack',
'$unwind_stack'.
scc_helper(_, _, _) :- scc_helper(_, _, _) :-
'$get_cp'(Cp), '$get_cp'(Cp),
run_cleaners_without_handling(Cp), run_cleaners_without_handling(Cp),
@@ -115,7 +111,7 @@ run_cleaners_with_handling :-
run_cleaners_without_handling(Cp) :- run_cleaners_without_handling(Cp) :-
'$get_scc_cleaner'(C), '$get_scc_cleaner'(C),
'$get_level'(B), '$get_level'(B),
'$call'(C), call(C),
'$set_cp_by_default'(B), '$set_cp_by_default'(B),
run_cleaners_without_handling(Cp). run_cleaners_without_handling(Cp).
run_cleaners_without_handling(Cp) :- run_cleaners_without_handling(Cp) :-
@@ -136,10 +132,13 @@ end_block(B, _Bb, NBb, L) :-
:- non_counted_backtracking handle_ile/3. :- non_counted_backtracking handle_ile/3.
handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :- !. handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :-
handle_ile(B, E, _) :- !,
'$pop_ball_stack'.
handle_ile(B, _, _) :-
'$remove_call_policy_check'(B), '$remove_call_policy_check'(B),
throw(E). '$pop_from_ball_stack',
'$unwind_stack'.
:- meta_predicate(call_with_inference_limit(0, ?, ?)). :- meta_predicate(call_with_inference_limit(0, ?, ?)).
@@ -170,21 +169,21 @@ install_inference_counter(B, L, Count0) :-
call_with_inference_limit(G, L, R, Bb, B) :- call_with_inference_limit(G, L, R, Bb, B) :-
'$install_new_block'(NBb), '$install_new_block'(NBb),
'$install_inference_counter'(B, L, Count0), '$install_inference_counter'(B, L, Count0),
'$call_with_inference_counting'('$call'(G)), '$call_with_inference_counting'(call(G)),
'$inference_level'(R, B), '$inference_level'(R, B),
'$remove_inference_counter'(B, Count1), '$remove_inference_counter'(B, Count1),
is(Diff, L - (Count1 - Count0)), Diff is L - (Count1 - Count0),
end_block(B, Bb, NBb, Diff). end_block(B, Bb, NBb, Diff).
call_with_inference_limit(_, _, R, Bb, B) :- call_with_inference_limit(_, _, R, Bb, B) :-
'$reset_block'(Bb), '$reset_block'(Bb),
'$remove_inference_counter'(B, _), '$remove_inference_counter'(B, _),
( '$get_ball'(Ball), ( '$get_ball'(Ball),
'$push_ball_stack',
'$get_level'(Cp), '$get_level'(Cp),
'$set_cp_by_default'(Cp) '$set_cp_by_default'(Cp)
; '$remove_call_policy_check'(B), ; '$remove_call_policy_check'(B),
'$fail' '$fail'
), ),
'$erase_ball',
handle_ile(B, Ball, R). handle_ile(B, Ball, R).
partial_string(String, L, L0) :- partial_string(String, L, L0) :-
@@ -250,3 +249,17 @@ call_nth_nesting(C, ID) :-
copy_term_nat(Source, Dest) :- copy_term_nat(Source, Dest) :-
'$copy_term_without_attr_vars'(Source, Dest). '$copy_term_without_attr_vars'(Source, Dest).
asserta(Module, (Head :- Body)) :-
!,
'$asserta'(Module, Head, Body).
asserta(Module, Fact) :-
'$asserta'(Module, Fact, true).
assertz(Module, (Head :- Body)) :-
!,
'$assertz'(Module, Head, Body).
assertz(Module, Fact) :-
'$assertz'(Module, Fact, true).

View File

@@ -1,7 +1,7 @@
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5, :- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
memberchk/2, reverse/2, length/2, maplist/2, memberchk/2, reverse/2, length/2, maplist/2,
maplist/3, maplist/4, maplist/5, maplist/6, maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, nth0/4, nth1/3, nth1/4,
sum_list/2, transpose/2, list_to_set/2, list_max/2, sum_list/2, transpose/2, list_to_set/2, list_max/2,
list_min/2, permutation/2]). list_min/2, permutation/2]).
@@ -243,27 +243,82 @@ unify_same(E-V, Prev-Var, E-V) :-
). ).
nth0(N, Es, E) :- nth0(N, Es0, E) :-
can_be(integer, N), nonvar(N),
can_be(list, Es), '$skip_max_list'(Skip, N, Es0,Es1),
( integer(N) -> !,
nth0_index(N, Es, E) ( Skip == N
; nth0_search(N, Es, E) -> Es1 = [E|_]
). ; ( var(Es1) ; Es1 = [_|_] ) % a partial or infinite list
-> R is N-Skip,
skipn(R,Es1,Es2),
Es2 = [E|_]
).
nth0(N, Es0, E) :-
can_be(not_less_than_zero, N),
Es0 = [E0|Es1],
nth0_el(0,N, E0,E, Es1).
nth0_index(0, [E|_], E) :- !. skipn(N0, Es0,Es) :-
nth0_index(N, [_|Es], E) :- N0>0,
N > 0, !, % should not be necessary #1028
N1 is N - 1, N1 is N0-1,
nth0_index(N1, Es, E). Es0 = [_|Es1],
skipn(N1, Es1,Es).
skipn(0, Es,Es).
nth0_search(N, Es, E) :- nth0_el(N0,N, E0,E, Es0) :-
nth0_search(0, N, Es, E). Es0 == [],
!, % indexing
N0 = N,
E0 = E.
nth0_el(N,N, E,E, _).
nth0_el(N0,N, _,E, [E0|Es0]) :-
N1 is N0+1,
nth0_el(N1,N, E0,E, Es0).
nth0_search(N, N, [E|_], E). nth1(N, Es0, E) :-
nth0_search(N0, N, [_|Es], E) :- N \== 0,
N1 is N0 + 1, nth0(N, [_|Es0], E),
nth0_search(N1, N, Es, E). N \== 0.
skipn(N0, Es0,Es, Xs0,Xs) :-
N0>0,
!, % should not be necessary #1028
N1 is N0-1,
Es0 = [E|Es1],
Xs0 = [E|Xs1],
skipn(N1, Es1,Es, Xs1,Xs).
skipn(0, Es,Es, Xs,Xs).
nth0(N, Es0, E, Es) :-
integer(N),
N >= 0,
!,
skipn(N, Es0,Es1, Es,Es2),
Es1 = [E|Es2].
nth0(N, Es0, E, Es) :-
can_be(not_less_than_zero, N),
Es0 = [E0|Es1],
nth0_elx(0,N, E0,E, Es1, Es).
nth0_elx(N0,N, E0,E, Es0, Es) :-
Es0 == [],
!,
N0 = N,
E0 = E,
Es0 = Es.
nth0_elx(N,N, E,E, Es, Es).
nth0_elx(N0,N, E0,E, [E1|Es0], [E0|Es]) :-
N1 is N0+1,
nth0_elx(N1,N, E1,E, Es0, Es).
% p.p.8.5
nth1(N, Es0, E, Es) :-
N \== 0,
nth0(N, [_|Es0], E, [_|Es]),
N \== 0.
list_max([N|Ns], Max) :- list_max([N|Ns], Max) :-

View File

@@ -5,7 +5,7 @@
map_list_to_pairs/3]). map_list_to_pairs/3]).
:- meta_predicate map_list_to_pairs(0, ?, ?). :- meta_predicate map_list_to_pairs(2, ?, ?).
pairs_keys_values([], [], []). pairs_keys_values([], [], []).
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :- pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-

View File

@@ -4,9 +4,9 @@
Our goal is to encourage the use of definite clause grammars (DCGs) Our goal is to encourage the use of definite clause grammars (DCGs)
for describing strings. The predicates phrase_from_file/[2,3], for describing strings. The predicates phrase_from_file/[2,3],
phrase_to_file/2 and phrase_to_stream/2 let us apply DCGs transparently phrase_to_file/[2,3] and phrase_to_stream/2 let us apply DCGs
to files and streams, and therefore decouple side-effects from transparently to files and streams, and therefore decouple side-effects
declarative descriptions. from declarative descriptions.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(pio, [phrase_from_file/2, :- module(pio, [phrase_from_file/2,
@@ -26,6 +26,7 @@
:- meta_predicate(phrase_from_file(2, ?)). :- meta_predicate(phrase_from_file(2, ?)).
:- meta_predicate(phrase_from_file(2, ?, ?)). :- meta_predicate(phrase_from_file(2, ?, ?)).
:- meta_predicate(phrase_to_file(2, ?)). :- meta_predicate(phrase_to_file(2, ?)).
:- meta_predicate(phrase_to_file(2, ?, ?)).
:- meta_predicate(phrase_to_stream(2, ?)). :- meta_predicate(phrase_to_stream(2, ?)).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -90,7 +91,7 @@ phrase_to_stream(GRBody, Stream) :-
must_be(chars, Cs), must_be(chars, Cs),
( stream_property(Stream, type(binary)) -> ( stream_property(Stream, type(binary)) ->
( '$first_non_octet'(Cs, N) -> ( '$first_non_octet'(Cs, N) ->
domain_error(byte_char, N, phrase_to_stream/2) domain_error(octet_character, N, phrase_to_stream/2)
; true ; true
) )
; true ; true

View File

@@ -1,6 +1,6 @@
:- module(reif, [if_/3, (=)/3, (',')/3, (;)/3, cond_t/3, dif/3, :- module(reif, [if_/3, (=)/3, (',')/3, (;)/3, cond_t/3, dif/3,
memberd_t/3, tfilter/3, tmember/2, tmember_t/3, memberd_t/3, tfilter/3, tmember/2, tmember_t/3,
tpartition/4]). tpartition/4]).
:- use_module(library(dif)). :- use_module(library(dif)).
@@ -30,13 +30,10 @@ non(false, true).
:- meta_predicate(tfilter(2, ?, ?)). :- meta_predicate(tfilter(2, ?, ?)).
tfilter(C_2, Es, Fs) :- tfilter(_, [], []).
i_tfilter(Es, C_2, Fs). tfilter(C_2, [E|Es], Fs0) :-
i_tfilter([], _, []).
i_tfilter([E|Es], C_2, Fs0) :-
if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs),
i_tfilter(Es, C_2, Fs). tfilter(C_2, Es, Fs).
:- meta_predicate(tpartition(2, ?, ?, ?)). :- meta_predicate(tpartition(2, ?, ?, ?)).

View File

@@ -27,7 +27,8 @@
:- module(si, [atom_si/1, :- module(si, [atom_si/1,
integer_si/1, integer_si/1,
atomic_si/1, atomic_si/1,
list_si/1]). list_si/1,
chars_si/1]).
:- use_module(library(lists)). :- use_module(library(lists)).
@@ -42,6 +43,16 @@ integer_si(I) :-
atomic_si(AC) :- atomic_si(AC) :-
functor(AC,_,0). functor(AC,_,0).
list_si(L) :- % list_si(L) :-
\+ \+ length(L, _), % \+ \+ length(L, _),
sort(L, _). % sort(L, _).
list_si(L0) :-
'$skip_max_list'(_,_, L0,L),
( nonvar(L) -> L = []
; throw(error(instantiation_error, list_si/1))
).
chars_si(Cs) :-
list_si(Cs),
'$is_partial_string'(Cs).

View File

@@ -1344,10 +1344,6 @@ print_row(R) :- maplist(print_row_, R), nl.
print_row_(N) :- format("~w ", [N]). print_row_(N) :- format("~w ", [N]).
nth1(N, Es, E) :-
N1 is N - 1,
nth0(N1, Es, E).
%?- transportation([1,1], [1,1], [[1,1],[1,1]], Ms). %?- transportation([1,1], [1,1], [[1,1],[1,1]], Ms).
%?- transportation([12,7,14], [3,15,9,6], [[20,50,10,60],[70,40,60,30],[40,80,70,40]], Ms). %?- transportation([12,7,14], [3,15,9,6], [[20,50,10,60],[70,40,60,30],[40,80,70,40]], Ms).

View File

@@ -67,7 +67,7 @@ table_and_status_for_variant(V,T,S) :-
tbd_table_status(T,S). tbd_table_status(T,S).
:- meta_predicate start_tabling(?, 0). :- meta_predicate start_tabling(?, :).
start_tabling(Wrapper,Worker) :- start_tabling(Wrapper,Worker) :-
put_new_trie_table_link, put_new_trie_table_link,

View File

@@ -4,8 +4,8 @@
numbervars(Term, N0, N) :- numbervars(Term, N0, N) :-
catch(internal_numbervars(Term, N0, N), catch(internal_numbervars(Term, N0, N),
error(E,Ctx), error(E,Ctx),
( ( var(Ctx) -> Ctx = numbervars/3 ; true ), throw(error(E,Ctx) ) ) ). ( ( var(Ctx) -> Ctx = numbervars/3 ; true ), throw(error(E,Ctx) ) ) ).
internal_numbervars(Term, N0, N) :- internal_numbervars(Term, N0, N) :-
must_be(integer, N0), must_be(integer, N0),

View File

@@ -26,22 +26,22 @@
:- use_module(library(http/http_open)). :- use_module(library(http/http_open)).
:- use_module(library(sgml)). :- use_module(library(sgml)).
:- use_module(library(lists)).
:- use_module(library(xpath)). :- use_module(library(xpath)).
:- use_module(library(dcgs)).
link_to_pl_file(File) :- link_to_pl_file(File) :-
http_open("https://github.com/mthom/scryer-prolog", S, []), http_open("https://github.com/mthom/scryer-prolog", S, []),
load_html(stream(S), DOM, []), load_html(stream(S), DOM, []),
xpath(DOM, //a(@href), File), xpath(DOM, //a(@href), File),
append(_, ".pl", File). phrase((...,".pl"), File).
Yielding: Yielding:
?- link_to_pl_file(File). ?- link_to_pl_file(File).
%@ File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl" %@ File = "/mthom/scryer-prolog/blob/master/src/lib/dcgs.pl"
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/dif.pl" %@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/pio.pl"
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/freeze.pl" %@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl"
%@ ; ... %@ ; ... .
Parts of the original functionality may not yet work. Please Parts of the original functionality may not yet work. Please
consider such parts opportunities for improvements, and file consider such parts opportunities for improvements, and file

File diff suppressed because it is too large Load Diff

View File

@@ -390,7 +390,6 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result<Number, MachineStubGen> { pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result<Number, MachineStubGen> {
if n2.is_negative() && n1.is_zero() { if n2.is_negative() && n1.is_zero() {
let stub_gen = move || functor_stub(culprit, 2); let stub_gen = move || functor_stub(culprit, 2);
return Err(undefined_eval_error(stub_gen)); return Err(undefined_eval_error(stub_gen));
} }
@@ -1183,7 +1182,7 @@ impl MachineState {
let result = arena_alloc!( let result = arena_alloc!(
drop_iter_on_err!(self, iter, rdiv(r1, r2)), drop_iter_on_err!(self, iter, rdiv(r1, r2)),
self.arena &mut self.arena
); );
self.interms.push(Number::Rational(result)); self.interms.push(Number::Rational(result));

View File

@@ -28,11 +28,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
sort(Modules0, Modules), sort(Modules0, Modules),
verify_attrs(Modules, Var, Value, ListOfGoalLists). verify_attrs(Modules, Var, Value, ListOfGoalLists).
error_handler(M, evaluation_error((M:verify_attributes)/3), []).
% error_handler(_, existence_error(procedure, verify_attributes/3), []).
verify_attrs([Module|Modules], Var, Value, [Module-Goals|ListOfGoalLists]) :- verify_attrs([Module|Modules], Var, Value, [Module-Goals|ListOfGoalLists]) :-
catch(Module:verify_attributes(Var, Value, Goals), catch(Module:verify_attributes(Var, Value, Goals),
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3), error(E, verify_attributes/3),
Goals = []), error_handler(Module, E, Goals)),
verify_attrs(Modules, Var, Value, ListOfGoalLists). verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([], _, _, []). verify_attrs([], _, _, []).

View File

@@ -406,7 +406,7 @@ fn merge_indexed_subsequences(
*o = 0; *o = 0;
return Some(IndexPtr::Index(outer_threaded_choice_instr_loc + 1)); return Some(IndexPtr::index(outer_threaded_choice_instr_loc + 1));
} }
_ => {} _ => {}
}, },
@@ -785,7 +785,7 @@ fn remove_non_leading_clause(
*o = 0; *o = 0;
Some(IndexPtr::Index(preceding_choice_instr_loc + 1)) Some(IndexPtr::index(preceding_choice_instr_loc + 1))
} }
_ => { _ => {
unreachable!(); unreachable!();
@@ -820,7 +820,7 @@ fn finalize_retract(
retraction_info, retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
index_ptr, index_ptr,
); );
} }
@@ -849,9 +849,9 @@ fn remove_leading_unindexed_clause(
retraction_info, retraction_info,
); );
Some(IndexPtr::Index(index_ptr)) Some(IndexPtr::index(index_ptr))
} else { } else {
Some(IndexPtr::DynamicUndefined) Some(IndexPtr::dynamic_undefined())
} }
} }
_ => { _ => {
@@ -1131,9 +1131,9 @@ fn prepend_compiled_clause(
}; };
if skeleton.core.is_dynamic { if skeleton.core.is_dynamic {
IndexPtr::DynamicIndex(clause_loc) IndexPtr::dynamic_index(clause_loc)
} else { } else {
IndexPtr::Index(clause_loc) IndexPtr::index(clause_loc)
} }
} }
@@ -1268,9 +1268,9 @@ fn append_compiled_clause(
code_ptr_opt.map(|p| { code_ptr_opt.map(|p| {
if skeleton.core.is_dynamic { if skeleton.core.is_dynamic {
IndexPtr::DynamicIndex(p) IndexPtr::dynamic_index(p)
} else { } else {
IndexPtr::Index(p) IndexPtr::index(p)
} }
}) })
} }
@@ -1306,8 +1306,8 @@ fn print_overwrite_warning(
} }
} }
match code_ptr { match code_ptr.tag() {
IndexPtr::DynamicUndefined | IndexPtr::Undefined => return, IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined => return,
_ if is_dynamic => return, _ if is_dynamic => return,
_ => {} _ => {}
} }
@@ -1471,16 +1471,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
); );
let index_ptr = if settings.is_dynamic() { let index_ptr = if settings.is_dynamic() {
IndexPtr::DynamicIndex(code_ptr) IndexPtr::dynamic_index(code_ptr)
} else { } else {
IndexPtr::Index(code_ptr) IndexPtr::index(code_ptr)
}; };
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&predicates.compilation_target, &predicates.compilation_target,
key, key,
&code_index, code_index,
index_ptr, index_ptr,
); );
@@ -1704,7 +1704,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
new_code_ptr, new_code_ptr,
); );
} }
@@ -1745,7 +1745,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
new_code_ptr, new_code_ptr,
); );
@@ -1870,7 +1870,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton.clauses[target_pos].clause_start; skeleton.clauses[target_pos].clause_start;
let index_ptr_opt = if target_pos == 0 { let index_ptr_opt = if target_pos == 0 {
Some(IndexPtr::Index(clause_loc)) Some(IndexPtr::index(clause_loc))
} else { } else {
None None
}; };
@@ -2384,13 +2384,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
match self.wam_prelude.indices.modules.get_mut(&filename) { match self.wam_prelude.indices.modules.get_mut(&filename) {
Some(ref mut module) => { Some(ref mut module) => {
let index_ptr = code_index.get(); let index_ptr = code_index.get();
let code_index = module.code_dir.entry(key).or_insert(code_index); let code_index = module.code_dir.entry(key)
.or_insert(code_index)
.clone();
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&CompilationTarget::Module(filename), &CompilationTarget::Module(filename),
key, key,
&code_index, code_index,
index_ptr, index_ptr,
); );
} }
@@ -2418,3 +2420,54 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Ok(()) Ok(())
} }
} }
// standalone functions for compiling auxiliary goals used by expand_goal.
impl Machine {
pub(crate) fn get_or_insert_qualified_code_index(
&mut self,
module_name: HeapCellValue,
key: PredicateKey,
) -> CodeIndex {
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(
self,
InlineTermStream {},
);
let module_name = if module_name.get_tag() == HeapCellValueTag::Atom {
cell_as_atom!(module_name)
} else {
atom!("user")
};
loader.get_or_insert_qualified_code_index(module_name, key)
}
pub(crate) fn compile_standalone_clause(
&mut self,
term_loc: RegType,
vars: &[Term],
) -> Result<(), SessionError> {
let mut compile = || {
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(
self,
InlineTermStream {},
);
let term = loader.read_term_from_heap(term_loc)?;
let clause = build_rule_body(vars, term);
let settings = CodeGenSettings {
global_clock_tick: None,
is_extensible: false,
non_counted_bt: true,
};
loader.compile_standalone_clause(clause, settings)
};
let StandaloneCompileResult { clause_code, .. } = compile()?;
self.code.extend(clause_code.into_iter());
Ok(())
}
}

View File

@@ -1,4 +1,5 @@
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::get_structure_index;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::types::*; use crate::types::*;
@@ -248,6 +249,14 @@ impl<T: CopierTarget> CopyTermState<T> {
let hcv = self.target[addr + 1 + i]; let hcv = self.target[addr + 1 + i];
self.target.push(hcv); self.target.push(hcv);
} }
let index_cell = self.target[addr + 1 + arity];
if get_structure_index(index_cell).is_some() {
// copy the index pointer trailing this
// inlined or expanded goal.
self.target.push(index_cell);
}
} }
(HeapCellValueTag::Str, h) => { (HeapCellValueTag::Str, h) => {
*self.value_at_scan() = str_loc_as_cell!(h); *self.value_at_scan() = str_loc_as_cell!(h);

View File

@@ -57,18 +57,28 @@ impl MachineState {
let a2 = self.registers[2]; let a2 = self.registers[2];
let a3 = self.registers[3]; let a3 = self.registers[3];
let check_atom = |machine_st: &mut MachineState, name: Atom, arity: usize| -> Result<(), MachineStub> {
match name {
atom!(">") | atom!("<") | atom!("=") if arity == 0 => {
Ok(())
}
_ => {
let err = machine_st.domain_error(DomainErrorType::Order, a1);
Err(machine_st.error_form(err, stub_gen()))
}
}
};
read_heap_cell!(a1, read_heap_cell!(a1,
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
check_atom(self, name, arity)?;
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
match name { check_atom(self, name, arity)?;
atom!(">") | atom!("<") | atom!("=") => {
}
_ => {
let err = self.domain_error(DomainErrorType::Order, a1);
return Err(self.error_form(err, stub_gen()));
}
}
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
} }
@@ -360,8 +370,15 @@ impl Machine {
debug_assert!(arity == 0); debug_assert!(arity == 0);
c c
} }
(HeapCellValueTag::Str) => { (HeapCellValueTag::Str, st) => {
s let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[st])
.get_name_and_arity();
match (name, arity) {
(atom!("."), 2) => l,
(_, 0) => c,
_ => s,
}
} }
(HeapCellValueTag::Cons, ptr) => { (HeapCellValueTag::Cons, ptr) => {
match ptr.get_tag() { match ptr.get_tag() {
@@ -421,6 +438,9 @@ impl Machine {
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
Literal::Atom(atom) Literal::Atom(atom)
} }
(HeapCellValueTag::Str, s) => {
Literal::Atom(cell_as_atom_cell!(self.machine_st.heap[s]).get_name())
}
(HeapCellValueTag::Cons, cons_ptr) => { (HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr, match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Rational, r) => { (ArenaHeaderTag::Rational, r) => {
@@ -597,6 +617,7 @@ impl Machine {
&mut self.machine_st, &mut self.machine_st,
try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen) try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
); );
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::Mul(ref a1, ref a2, t) => { &Instruction::Mul(ref a1, ref a2, t) => {
@@ -675,7 +696,7 @@ impl Machine {
self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!( self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)), try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
self.machine_st.arena &mut self.machine_st.arena
)); ));
self.machine_st.p += 1; self.machine_st.p += 1;
@@ -688,6 +709,7 @@ impl Machine {
&mut self.machine_st, &mut self.machine_st,
int_floor_div(n1, n2, &mut self.machine_st.arena) int_floor_div(n1, n2, &mut self.machine_st.arena)
); );
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::IDiv(ref a1, ref a2, t) => { &Instruction::IDiv(ref a1, ref a2, t) => {
@@ -698,6 +720,7 @@ impl Machine {
&mut self.machine_st, &mut self.machine_st,
idiv(n1, n2, &mut self.machine_st.arena) idiv(n1, n2, &mut self.machine_st.arena)
); );
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::Abs(ref a1, t) => { &Instruction::Abs(ref a1, t) => {
@@ -1122,17 +1145,7 @@ impl Machine {
); );
} }
&Instruction::NeckCut => { &Instruction::NeckCut => {
let b = self.machine_st.b; self.machine_st.neck_cut();
let b0 = self.machine_st.b0;
if b > b0 {
self.machine_st.b = b0;
if b > self.machine_st.e {
self.machine_st.stack.truncate(b);
}
}
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::GetLevel(r) => { &Instruction::GetLevel(r) => {
@@ -1298,7 +1311,6 @@ impl Machine {
} }
&Instruction::DefaultCallRead(_) => { &Instruction::DefaultCallRead(_) => {
try_or_throw!(self.machine_st, self.read()); try_or_throw!(self.machine_st, self.read());
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);
} }
&Instruction::DefaultExecuteRead(_) => { &Instruction::DefaultExecuteRead(_) => {
@@ -2354,6 +2366,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p += 1;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Char) => { (HeapCellValueTag::Char) => {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
@@ -2373,6 +2395,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p = self.machine_st.cp;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Char) => { (HeapCellValueTag::Char) => {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
@@ -2396,6 +2428,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p += 1;
} else {
self.machine_st.backtrack();
}
}
_ => { _ => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -2416,6 +2458,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p = self.machine_st.cp;
} else {
self.machine_st.backtrack();
}
}
_ => { _ => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -2425,10 +2477,21 @@ impl Machine {
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
read_heap_cell!(d, read_heap_cell!(d,
(HeapCellValueTag::Str | HeapCellValueTag::Lis | (HeapCellValueTag::Lis |
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr) => {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity > 0 {
self.machine_st.p += 1;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Atom, (_name, arity)) => { (HeapCellValueTag::Atom, (_name, arity)) => {
if arity > 0 { if arity > 0 {
self.machine_st.p += 1; self.machine_st.p += 1;
@@ -2445,10 +2508,21 @@ impl Machine {
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
read_heap_cell!(d, read_heap_cell!(d,
(HeapCellValueTag::Str | HeapCellValueTag::Lis | (HeapCellValueTag::Lis |
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr) => {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity > 0 {
self.machine_st.p = self.machine_st.cp;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Atom, (_name, arity)) => { (HeapCellValueTag::Atom, (_name, arity)) => {
if arity > 0 { if arity > 0 {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
@@ -2744,6 +2818,19 @@ impl Machine {
self.machine_st.s_offset = 0; self.machine_st.s_offset = 0;
self.machine_st.mode = MachineMode::Read; self.machine_st.mode = MachineMode::Read;
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if name == atom!(".") && arity == 2 {
self.machine_st.s = HeapPtr::HeapCell(s+1);
self.machine_st.s_offset = 0;
self.machine_st.mode = MachineMode::Read;
} else {
self.machine_st.backtrack();
continue;
}
}
(HeapCellValueTag::Lis, l) => { (HeapCellValueTag::Lis, l) => {
self.machine_st.s = HeapPtr::HeapCell(l); self.machine_st.s = HeapPtr::HeapCell(l);
self.machine_st.s_offset = 0; self.machine_st.s_offset = 0;
@@ -3500,7 +3587,10 @@ impl Machine {
self.dynamic_module_resolution(arity - 2) self.dynamic_module_resolution(arity - 2)
); );
try_or_throw!(self.machine_st, self.call_clause(module_name, key)); try_or_throw!(
self.machine_st,
self.call_clause(module_name, key)
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -3512,7 +3602,10 @@ impl Machine {
self.dynamic_module_resolution(arity - 2) self.dynamic_module_resolution(arity - 2)
); );
try_or_throw!(self.machine_st, self.execute_clause(module_name, key)); try_or_throw!(
self.machine_st,
self.execute_clause(module_name, key)
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -4032,14 +4125,6 @@ impl Machine {
self.clean_up_block(); self.clean_up_block();
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
&Instruction::CallEraseBall(_) => {
self.erase_ball();
self.machine_st.p += 1;
}
&Instruction::ExecuteEraseBall(_) => {
self.erase_ball();
self.machine_st.p = self.machine_st.cp;
}
&Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => { &Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -4123,6 +4208,30 @@ impl Machine {
try_or_throw!(self.machine_st, self.http_open()); try_or_throw!(self.machine_st, self.http_open());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp); step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallHttpListen(_) => {
try_or_throw!(self.machine_st, self.http_listen());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteHttpListen(_) => {
try_or_throw!(self.machine_st, self.http_listen());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallHttpAccept(_) => {
try_or_throw!(self.machine_st, self.http_accept());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteHttpAccept(_) => {
try_or_throw!(self.machine_st, self.http_accept());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallHttpAnswer(_) => {
try_or_throw!(self.machine_st, self.http_answer());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteHttpAnswer(_) => {
try_or_throw!(self.machine_st, self.http_answer());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCurrentTime(_) => { &Instruction::CallCurrentTime(_) => {
self.current_time(); self.current_time();
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);
@@ -4167,6 +4276,30 @@ impl Machine {
self.set_ball(); self.set_ball();
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
&Instruction::CallPushBallStack(_) => {
self.push_ball_stack();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecutePushBallStack(_) => {
self.push_ball_stack();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallPopBallStack(_) => {
self.pop_ball_stack();
self.machine_st.p += 1;
}
&Instruction::ExecutePopBallStack(_) => {
self.pop_ball_stack();
self.machine_st.p = self.machine_st.cp;
}
&Instruction::CallPopFromBallStack(_) => {
self.pop_from_ball_stack();
self.machine_st.p += 1;
}
&Instruction::ExecutePopFromBallStack(_) => {
self.pop_from_ball_stack();
self.machine_st.p = self.machine_st.cp;
}
&Instruction::CallSetCutPointByDefault(r, _) => { &Instruction::CallSetCutPointByDefault(r, _) => {
self.set_cut_point_by_default(r); self.set_cut_point_by_default(r);
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);
@@ -4853,11 +4986,11 @@ impl Machine {
} }
&Instruction::CallPredicateDefined(_) => { &Instruction::CallPredicateDefined(_) => {
self.machine_st.fail = !self.predicate_defined(); self.machine_st.fail = !self.predicate_defined();
self.machine_st.p += 1; step_or_fail!(self, self.machine_st.p += 1);
} }
&Instruction::ExecutePredicateDefined(_) => { &Instruction::ExecutePredicateDefined(_) => {
self.machine_st.fail = !self.predicate_defined(); self.machine_st.fail = !self.predicate_defined();
self.machine_st.p = self.machine_st.cp; step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallStripModule(_) => { &Instruction::CallStripModule(_) => {
let (module_loc, qualified_goal) = self.machine_st.strip_module( let (module_loc, qualified_goal) = self.machine_st.strip_module(
@@ -4886,7 +5019,7 @@ impl Machine {
&Instruction::ExecuteStripModule(_) => { &Instruction::ExecuteStripModule(_) => {
let (module_loc, qualified_goal) = self.machine_st.strip_module( let (module_loc, qualified_goal) = self.machine_st.strip_module(
self.machine_st.registers[1], self.machine_st.registers[1],
self.machine_st.registers[2] self.machine_st.registers[2],
); );
let target_module_loc = self.machine_st.registers[2]; let target_module_loc = self.machine_st.registers[2];
@@ -4915,6 +5048,54 @@ impl Machine {
try_or_throw!(self.machine_st, self.prepare_call_clause(arity)); try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
step_or_fail!(self, self.machine_st.p = self.machine_st.cp); step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallCompileInlineOrExpandedGoal(_) => {
try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteCompileInlineOrExpandedGoal(_) => {
try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallIsExpandedOrInlined(_) => {
self.machine_st.fail = !self.is_expanded_or_inlined();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteIsExpandedOrInlined(_) => {
self.machine_st.fail = !self.is_expanded_or_inlined();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallInlineCallN(arity, _) => {
let call_at_index = |wam: &mut Machine, name, arity, ptr| {
wam.try_call(name, arity, ptr)
};
try_or_throw!(self.machine_st, self.call_inline(arity, call_at_index));
if self.machine_st.fail {
self.machine_st.backtrack();
} else {
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
}
}
&Instruction::ExecuteInlineCallN(arity, _) => {
let call_at_index = |wam: &mut Machine, name, arity, ptr| {
wam.try_execute(name, arity, ptr)
};
try_or_throw!(self.machine_st, self.call_inline(arity, call_at_index));
if self.machine_st.fail {
self.machine_st.backtrack();
} else {
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
}
}
} }
} }

View File

@@ -2,6 +2,9 @@ use crate::atom_table::*;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::types::*; use crate::types::*;
#[cfg(test)]
use crate::heap_iter::FocusedHeapIter;
use core::marker::PhantomData; use core::marker::PhantomData;
pub(crate) trait UnmarkPolicy { pub(crate) trait UnmarkPolicy {
@@ -69,6 +72,14 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
_marker: PhantomData<UMP>, _marker: PhantomData<UMP>,
} }
#[cfg(test)]
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[inline]
fn focus(&self) -> usize {
self.current
}
}
impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
fn drop(&mut self) { fn drop(&mut self) {
if self.current == self.start { if self.current == self.start {

View File

@@ -1,6 +1,7 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::types::*; use crate::types::*;
@@ -17,6 +18,9 @@ impl From<Literal> for HeapCellValue {
match literal { match literal {
Literal::Atom(name) => atom_as_cell!(name), Literal::Atom(name) => atom_as_cell!(name),
Literal::Char(c) => char_as_cell!(c), Literal::Char(c) => char_as_cell!(c),
Literal::CodeIndex(ptr) => {
untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
}
Literal::Fixnum(n) => fixnum_as_cell!(n), Literal::Fixnum(n) => fixnum_as_cell!(n),
Literal::Integer(bigint_ptr) => { Literal::Integer(bigint_ptr) => {
typed_arena_ptr_as_cell!(bigint_ptr) typed_arena_ptr_as_cell!(bigint_ptr)
@@ -65,6 +69,9 @@ impl TryFrom<HeapCellValue> for Literal {
(ArenaHeaderTag::Rational, n) => { (ArenaHeaderTag::Rational, n) => {
Ok(Literal::Rational(n)) Ok(Literal::Rational(n))
} }
(ArenaHeaderTag::IndexPtr, _ip) => {
Ok(Literal::CodeIndex(CodeIndex::from(cons_ptr)))
}
_ => { _ => {
Err(()) Err(())
} }

View File

@@ -21,12 +21,12 @@ pub(super) fn set_code_index(
retraction_info: &mut RetractionInfo, retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
key: PredicateKey, key: PredicateKey,
code_index: &CodeIndex, mut code_index: CodeIndex,
code_ptr: IndexPtr, code_ptr: IndexPtr,
) { ) {
let record = match compilation_target { let record = match compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
if IndexPtr::Undefined == code_index.get() { if IndexPtrTag::Undefined == code_index.get().tag() {
code_index.set(code_ptr); code_index.set(code_ptr);
RetractionRecord::AddedUserPredicate(key) RetractionRecord::AddedUserPredicate(key)
} else { } else {
@@ -35,7 +35,7 @@ pub(super) fn set_code_index(
} }
} }
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
if IndexPtr::Undefined == code_index.get() { if IndexPtrTag::Undefined == code_index.get().tag() {
code_index.set(code_ptr); code_index.set(code_ptr);
RetractionRecord::AddedModulePredicate(*module_name, key) RetractionRecord::AddedModulePredicate(*module_name, key)
} else { } else {
@@ -48,12 +48,10 @@ pub(super) fn set_code_index(
retraction_info.push_record(record); retraction_info.push_record(record);
} }
fn add_op_decl_as_module_export( fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
payload: &mut LS::LoaderFieldType,
module_op_dir: &mut OpDir, module_op_dir: &mut OpDir,
compilation_target: &CompilationTarget,
retraction_info: &mut RetractionInfo,
wam_op_dir: &mut OpDir, wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
op_decl: &OpDecl, op_decl: &OpDecl,
) { ) {
/* /*
@@ -65,20 +63,21 @@ fn add_op_decl_as_module_export(
match op_decl.insert_into_op_dir(wam_op_dir) { match op_decl.insert_into_op_dir(wam_op_dir) {
Some(op_desc) => { Some(op_desc) => {
retraction_info.push_record(RetractionRecord::ReplacedUserOp( payload.retraction_info.push_record(RetractionRecord::ReplacedUserOp(
*op_decl, *op_decl,
op_desc, op_desc,
)); ));
module_op_exports.push((*op_decl, Some(op_desc))); payload.module_op_exports.push((*op_decl, Some(op_desc)));
} }
None => { None => {
retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); payload.retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
module_op_exports.push((*op_decl, None)); payload.module_op_exports.push((*op_decl, None));
} }
} }
add_op_decl(retraction_info, compilation_target, module_op_dir, op_decl); let compilation_target = payload.compilation_target;
add_op_decl(&mut payload.retraction_info, &compilation_target, module_op_dir, op_decl);
} }
pub(super) fn add_op_decl( pub(super) fn add_op_decl(
@@ -117,8 +116,8 @@ pub(super) fn add_op_decl(
} }
} }
pub(super) fn import_module_exports( pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
@@ -135,16 +134,18 @@ pub(super) fn import_module_exports(
} }
if let Some(src_code_index) = imported_module.code_dir.get(&key) { if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let arena = &mut LS::machine_st(payload).arena;
let target_code_index = code_dir let target_code_index = code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::default(arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -155,7 +156,7 @@ pub(super) fn import_module_exports(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl(retraction_info, compilation_target, op_dir, op_decl); add_op_decl(&mut payload.retraction_info, compilation_target, op_dir, op_decl);
} }
} }
} }
@@ -163,15 +164,14 @@ pub(super) fn import_module_exports(
Ok(()) Ok(())
} }
fn import_module_exports_into_module( fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
op_dir: &mut OpDir, op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir, meta_predicates: &mut MetaPredicateDir,
wam_op_dir: &mut OpDir, wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
for export in imported_module.module_decl.exports.iter() { for export in imported_module.module_decl.exports.iter() {
match export { match export {
@@ -183,16 +183,18 @@ fn import_module_exports_into_module(
} }
if let Some(src_code_index) = imported_module.code_dir.get(&key) { if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let arena = &mut LS::machine_st(payload).arena;
let target_code_index = code_dir let target_code_index = code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::default(arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -203,12 +205,10 @@ fn import_module_exports_into_module(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export( add_op_decl_as_module_export::<LS>(
payload,
op_dir, op_dir,
compilation_target,
retraction_info,
wam_op_dir, wam_op_dir,
module_op_exports,
op_decl, op_decl,
); );
} }
@@ -218,14 +218,12 @@ fn import_module_exports_into_module(
Ok(()) Ok(())
} }
fn import_qualified_module_exports( fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
exports: &IndexSet<ModuleExport>, exports: &IndexSet<ModuleExport>,
code_dir: &mut CodeDir, wam_prelude: &mut MachinePreludeView,
op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
for export in imported_module.module_decl.exports.iter() { for export in imported_module.module_decl.exports.iter() {
if !exports.contains(export) { if !exports.contains(export) {
@@ -237,20 +235,22 @@ fn import_qualified_module_exports(
let key = (*name, *arity); let key = (*name, *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
meta_predicates.insert(key.clone(), meta_specs.clone()); wam_prelude.indices.meta_predicates.insert(key.clone(), meta_specs.clone());
} }
if let Some(src_code_index) = imported_module.code_dir.get(&key) { if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir let arena = &mut LS::machine_st(payload).arena;
let target_code_index = wam_prelude.indices.code_dir
.entry(key.clone()) .entry(key.clone())
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -261,7 +261,12 @@ fn import_qualified_module_exports(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl(retraction_info, compilation_target, op_dir, op_decl); add_op_decl(
&mut payload.retraction_info,
compilation_target,
&mut wam_prelude.indices.op_dir,
op_decl,
);
} }
} }
} }
@@ -269,17 +274,17 @@ fn import_qualified_module_exports(
Ok(()) Ok(())
} }
fn import_qualified_module_exports_into_module( fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
exports: &IndexSet<ModuleExport>, exports: &IndexSet<ModuleExport>,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
op_dir: &mut OpDir, op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir, meta_predicates: &mut MetaPredicateDir,
wam_op_dir: &mut OpDir, wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let payload_compilation_target = payload.compilation_target;
for export in imported_module.module_decl.exports.iter() { for export in imported_module.module_decl.exports.iter() {
if !exports.contains(export) { if !exports.contains(export) {
continue; continue;
@@ -294,16 +299,18 @@ fn import_qualified_module_exports_into_module(
} }
if let Some(src_code_index) = imported_module.code_dir.get(&key) { if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let arena = &mut LS::machine_st(payload).arena;
let target_code_index = code_dir let target_code_index = code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, &payload_compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -314,12 +321,10 @@ fn import_qualified_module_exports_into_module(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export( add_op_decl_as_module_export::<LS>(
payload,
op_dir, op_dir,
compilation_target,
retraction_info,
wam_op_dir, wam_op_dir,
module_op_exports,
op_decl, op_decl,
); );
} }
@@ -464,7 +469,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
None => return, None => return,
}; };
for (key, code_index) in &removed_module.code_dir { for (key, code_index) in removed_module.code_dir.iter_mut() {
match removed_module match removed_module
.local_extensible_predicates .local_extensible_predicates
.get(&(CompilationTarget::User, *key)) .get(&(CompilationTarget::User, *key))
@@ -473,7 +478,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
_ => {} _ => {}
} }
let old_index_ptr = code_index.replace(IndexPtr::Undefined); let old_index_ptr = code_index.replace(IndexPtr::undefined());
self.payload.retraction_info self.payload.retraction_info
.push_record(RetractionRecord::ReplacedModulePredicate( .push_record(RetractionRecord::ReplacedModulePredicate(
@@ -512,11 +517,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
for export in removed_module.module_decl.exports.iter() { for export in removed_module.module_decl.exports.iter() {
match export { match export {
ModuleExport::PredicateKey(ref key) => { ModuleExport::PredicateKey(ref key) => {
match (removed_module.code_dir.get(key), code_dir.get(key)) { match (removed_module.code_dir.get(key), code_dir.get_mut(key)) {
(Some(module_code_index), Some(target_code_index)) (Some(module_code_index), Some(target_code_index))
if module_code_index.get() == target_code_index.get() => if module_code_index.get() == target_code_index.get() =>
{ {
let old_index_ptr = target_code_index.replace(IndexPtr::Undefined); let old_index_ptr = target_code_index.replace(IndexPtr::undefined());
retraction_info.push_record(predicate_retractor(*key, old_index_ptr)); retraction_info.push_record(predicate_retractor(*key, old_index_ptr));
} }
_ => {} _ => {}
@@ -584,7 +589,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Some(ref mut module) => module Some(ref mut module) => module
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(
IndexPtr::undefined(),
&mut LS::machine_st(&mut self.payload).arena,
))
.clone(), .clone(),
None => { None => {
self.add_dynamically_generated_module(module_name); self.add_dynamically_generated_module(module_name);
@@ -593,7 +601,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Some(ref mut module) => module Some(ref mut module) => module
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(
IndexPtr::undefined(),
&mut LS::machine_st(&mut self.payload).arena,
))
.clone(), .clone(),
None => { None => {
unreachable!() unreachable!()
@@ -608,13 +619,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
key: PredicateKey, key: PredicateKey,
compilation_target: CompilationTarget, compilation_target: CompilationTarget,
) -> CodeIndex { ) -> CodeIndex {
let arena = &mut LS::machine_st(&mut self.payload).arena;
match compilation_target { match compilation_target {
CompilationTarget::User => self CompilationTarget::User => self
.wam_prelude .wam_prelude
.indices .indices
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(), .clone(),
CompilationTarget::Module(module_name) => { CompilationTarget::Module(module_name) => {
self.get_or_insert_local_code_index(module_name, key) self.get_or_insert_local_code_index(module_name, key)
@@ -627,13 +640,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
module_name: Atom, module_name: Atom,
key: PredicateKey, key: PredicateKey,
) -> CodeIndex { ) -> CodeIndex {
let arena = &mut LS::machine_st(&mut self.payload).arena;
if module_name == atom!("user") { if module_name == atom!("user") {
return self return self
.wam_prelude .wam_prelude
.indices .indices
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(); .clone();
} else { } else {
self.get_or_insert_local_code_index(module_name, key) self.get_or_insert_local_code_index(module_name, key)
@@ -732,14 +747,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
match self.wam_prelude.indices.modules.get_mut(module_name) { match self.wam_prelude.indices.modules.get_mut(module_name) {
Some(ref mut module) => { Some(ref mut module) => {
let payload: &mut LoadStatePayload<_> = &mut self.payload; add_op_decl_as_module_export::<LS>(
&mut self.payload,
add_op_decl_as_module_export(
&mut module.op_dir, &mut module.op_dir,
&payload.compilation_target,
&mut payload.retraction_info,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports,
op_decl, op_decl,
); );
} }
@@ -752,7 +763,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType { pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType {
match ClauseType::from(name, arity) { let arena = &mut LS::machine_st(&mut self.payload).arena;
match ClauseType::from(name, arity, arena) {
ClauseType::Named(arity, name, _) => { ClauseType::Named(arity, name, _) => {
let payload_compilation_target = self.payload.compilation_target; let payload_compilation_target = self.payload.compilation_target;
@@ -773,7 +786,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
name: Atom, name: Atom,
arity: usize, arity: usize,
) -> ClauseType { ) -> ClauseType {
match ClauseType::from(name, arity) { let arena = &mut LS::machine_st(&mut self.payload).arena;
match ClauseType::from(name, arity, arena) {
ClauseType::Named(arity, name, _) => { ClauseType::Named(arity, name, _) => {
let key = (name, arity); let key = (name, arity);
let idx = self.get_or_insert_qualified_code_index(module_name, key); let idx = self.get_or_insert_qualified_code_index(module_name, key);
@@ -784,6 +799,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
} }
pub(super) fn get_meta_specs(&self, name: Atom, arity: usize) -> Option<&Vec<MetaSpec>> {
self.wam_prelude
.indices
.get_meta_predicate_spec(
name,
arity,
&self.payload.compilation_target,
)
}
pub(super) fn add_meta_predicate_record( pub(super) fn add_meta_predicate_record(
&mut self, &mut self,
module_name: Atom, module_name: Atom,
@@ -894,8 +919,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
return; return;
} }
import_module_exports( import_module_exports::<LS>(
&mut self.payload.retraction_info, &mut self.payload,
&module_compilation_target, &module_compilation_target,
builtins, builtins,
code_dir, code_dir,
@@ -992,14 +1017,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
for export in &module.module_decl.exports { for export in &module.module_decl.exports {
if let ModuleExport::OpDecl(ref op_decl) = export { if let ModuleExport::OpDecl(ref op_decl) = export {
let payload: &mut LoadStatePayload<_> = &mut self.payload; add_op_decl_as_module_export::<LS>(
&mut self.payload,
add_op_decl_as_module_export(
&mut module.op_dir, &mut module.op_dir,
&payload.compilation_target, // this is a Module.
&mut payload.retraction_info,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports,
op_decl, op_decl,
); );
} }
@@ -1018,8 +1039,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
match &payload_compilation_target { match &payload_compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
import_module_exports( import_module_exports::<LS>(
&mut self.payload.retraction_info, &mut self.payload,
&payload_compilation_target, &payload_compilation_target,
&module, &module,
&mut self.wam_prelude.indices.code_dir, &mut self.wam_prelude.indices.code_dir,
@@ -1030,17 +1051,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
CompilationTarget::Module(ref defining_module_name) => { CompilationTarget::Module(ref defining_module_name) => {
match self.wam_prelude.indices.modules.get_mut(defining_module_name) { match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
Some(ref mut target_module) => { Some(ref mut target_module) => {
let payload: &mut LoadStatePayload<_> = &mut self.payload; import_module_exports_into_module::<LS>(
&mut self.payload,
import_module_exports_into_module(
&mut payload.retraction_info,
&payload_compilation_target, &payload_compilation_target,
&module, &module,
&mut target_module.code_dir, &mut target_module.code_dir,
&mut target_module.op_dir, &mut target_module.op_dir,
&mut target_module.meta_predicates, &mut target_module.meta_predicates,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports,
)?; )?;
} }
None => { None => {
@@ -1070,47 +1088,38 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) { if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) {
let payload_compilation_target = self.payload.compilation_target; let payload_compilation_target = self.payload.compilation_target;
match &payload_compilation_target { let result = match &payload_compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
import_qualified_module_exports( import_qualified_module_exports::<LS>(
&mut self.payload.retraction_info, &mut self.payload,
&payload_compilation_target, &payload_compilation_target,
&module, &module,
&exports, &exports,
&mut self.wam_prelude.indices.code_dir, &mut self.wam_prelude,
&mut self.wam_prelude.indices.op_dir, )
&mut self.wam_prelude.indices.meta_predicates,
)?;
} }
CompilationTarget::Module(ref defining_module_name) => { CompilationTarget::Module(ref defining_module_name) => {
match self.wam_prelude.indices.modules.get_mut(defining_module_name) { match self.wam_prelude.indices.modules.get_mut(defining_module_name) {
Some(ref mut target_module) => { Some(ref mut target_module) => {
let payload: &mut LoadStatePayload<_> = &mut self.payload; import_qualified_module_exports_into_module::<LS>(
&mut self.payload,
import_qualified_module_exports_into_module(
&mut payload.retraction_info,
&payload_compilation_target,
&module, &module,
&exports, &exports,
&mut target_module.code_dir, &mut target_module.code_dir,
&mut target_module.op_dir, &mut target_module.op_dir,
&mut target_module.meta_predicates, &mut target_module.meta_predicates,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports, )
)?;
} }
None => { None => {
// we find ourselves here because we're trying to import Err(SessionError::ModuleCannotImportSelf(module_name))
// a module into itself as it is being defined.
self.wam_prelude.indices.modules.insert(module_name, module);
return Err(SessionError::ModuleCannotImportSelf(module_name));
} }
} }
} }
} };
self.wam_prelude.indices.modules.insert(module_name, module); self.wam_prelude.indices.modules.insert(module_name, module);
Ok(()) result
} else { } else {
Err(SessionError::ExistenceError(ExistenceError::Module(module_name))) Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
} }
@@ -1168,7 +1177,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
indices: self.wam_prelude.indices, indices: self.wam_prelude.indices,
code: self.wam_prelude.code, code: self.wam_prelude.code,
load_contexts: self.wam_prelude.load_contexts, load_contexts: self.wam_prelude.load_contexts,
} },
}; };
subloader.load()? subloader.load()?
@@ -1231,7 +1240,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
indices: self.wam_prelude.indices, indices: self.wam_prelude.indices,
code: self.wam_prelude.code, code: self.wam_prelude.code,
load_contexts: self.wam_prelude.load_contexts, load_contexts: self.wam_prelude.load_contexts,
} },
}; };
subloader.load()? subloader.load()?

View File

@@ -390,6 +390,64 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
} }
} }
pub struct InlineLoadState<'a> {
machine_st: &'a mut MachineState,
pub payload: LoadStatePayload<InlineTermStream>,
}
impl<'a> Deref for InlineLoadState<'a> {
type Target = LoadStatePayload<InlineTermStream>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.payload
}
}
impl<'a> DerefMut for InlineLoadState<'a> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.payload
}
}
impl<'a> LoadState<'a> for InlineLoadState<'a> {
type TS = InlineTermStream;
type LoaderFieldType = InlineLoadState<'a>;
type Evacuable = ();
#[inline(always)]
fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload<Self::TS>) -> Self::LoaderFieldType {
InlineLoadState { machine_st, payload }
}
fn evacuate(_loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError> {
Ok(())
}
#[inline(always)]
fn should_drop_load_state(_loader: &Loader<'a, Self>) -> bool {
false
}
#[inline(always)]
fn reset_machine(_loader: &mut Loader<'a, Self>) {
}
#[inline(always)]
fn machine_st(load_state: &mut Self::LoaderFieldType) -> &mut MachineState {
&mut load_state.machine_st
}
#[inline(always)]
fn err_on_builtin_overwrite(
_loader: &Loader<'a, Self>,
_key: PredicateKey,
) -> Result<(), SessionError> {
Ok(())
}
}
pub struct Loader<'a, LS: LoadState<'a>> { pub struct Loader<'a, LS: LoadState<'a>> {
pub(super) payload: LS::LoaderFieldType, pub(super) payload: LS::LoaderFieldType,
pub(super) wam_prelude: MachinePreludeView<'a>, pub(super) wam_prelude: MachinePreludeView<'a>,
@@ -510,6 +568,27 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
} }
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
let h = iter.focus();
let mut arity = arity;
if iter.heap.len() > h + arity + 1 {
let value = iter.heap[h + arity + 1];
if let Some(idx) = get_structure_index(value) {
// in the second condition, arity == 0,
// meaning idx cannot pertain to this atom
// if it is the direct subterm of a larger
// structure.
if arity > 0 || !iter.direct_subterm_of_str(h) {
term_stack.push(
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
);
arity += 1;
}
}
}
if arity == 0 { if arity == 0 {
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
} else { } else {
@@ -708,7 +787,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
module module
.code_dir .code_dir
.get_mut(&key) .get_mut(&key)
.map(|code_idx| code_idx.replace(old_code_idx)); .map(|code_idx| code_idx.set(old_code_idx));
} }
None => {} None => {}
} }
@@ -733,10 +812,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.indices .indices
.code_dir .code_dir
.get_mut(&key) .get_mut(&key)
.map(|code_idx| code_idx.replace(old_code_idx)); .map(|code_idx| code_idx.set(old_code_idx));
} }
RetractionRecord::AddedIndex(index_key, clause_loc) => { RetractionRecord::AddedIndex(index_key, clause_loc) => {
// WAS: inner_index_locs) => {
if let Some(index_loc) = index_key.switch_on_term_loc() { if let Some(index_loc) = index_key.switch_on_term_loc() {
let indexing_code = match &mut self.wam_prelude.code[index_loc] { let indexing_code = match &mut self.wam_prelude.code[index_loc] {
Instruction::IndexingCode(indexing_code) => indexing_code, Instruction::IndexingCode(indexing_code) => indexing_code,
@@ -1271,13 +1349,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let code_index = self.get_or_insert_code_index(key, compilation_target); let code_index = self.get_or_insert_code_index(key, compilation_target);
if let IndexPtr::Undefined = code_index.get() { if code_index.is_undefined() {
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
IndexPtr::DynamicUndefined, IndexPtr::dynamic_undefined(),
); );
} }
} }
@@ -1491,7 +1569,6 @@ impl Machine {
let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
let declare_module = || { let declare_module = || {
// let export_list = export_list?;
let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?; let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?;
let module_decl = ModuleDecl { let module_decl = ModuleDecl {
@@ -1885,13 +1962,10 @@ impl Machine {
} }
} }
pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) -> CallResult { pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) -> CallResult
let key = self {
.machine_st
.read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]);
let module_name = cell_as_atom!( let module_name = cell_as_atom!(
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[5])) self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
); );
let compilation_target = match module_name { let compilation_target = match module_name {
@@ -1899,14 +1973,62 @@ impl Machine {
_ => CompilationTarget::Module(module_name), _ => CompilationTarget::Module(module_name),
}; };
let stub_gen = || {
match append_or_prepend {
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
}
};
let mut compile_assert = || { let mut compile_assert = || {
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
Loader::new(self, LiveTermStream::new(ListingSource::User)); Loader::new(self, LiveTermStream::new(ListingSource::User));
loader.payload.compilation_target = compilation_target; loader.payload.compilation_target = compilation_target;
let head = loader.read_term_from_heap(temp_v!(1))?; let head = loader.read_term_from_heap(temp_v!(2))?;
let body = loader.read_term_from_heap(temp_v!(2))?;
let name = if let Some(name) = head.name() {
name
} else {
return Err(SessionError::from(CompilationError::InvalidRuleHead));
};
let arity = head.arity();
let is_dynamic_predicate = loader
.wam_prelude
.indices
.is_dynamic_predicate(
module_name,
(name, arity),
);
let no_such_predicate =
if !is_dynamic_predicate && !ClauseType::is_inbuilt(name, arity) {
let idx_tag = loader
.wam_prelude
.indices
.get_predicate_code_index(
name,
arity,
module_name,
)
.map(|code_idx| code_idx.get_tag())
.unwrap_or(IndexPtrTag::DynamicUndefined);
idx_tag == IndexPtrTag::DynamicUndefined ||
idx_tag == IndexPtrTag::Undefined
} else {
is_dynamic_predicate
};
if !no_such_predicate {
LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = true;
return LiveLoadAndMachineState::evacuate(loader);
}
let body = loader.read_term_from_heap(temp_v!(3))?;
let asserted_clause = Term::Clause( let asserted_clause = Term::Clause(
Cell::default(), Cell::default(),
@@ -1915,10 +2037,10 @@ impl Machine {
); );
// if a new predicate was just created, make it dynamic. // if a new predicate was just created, make it dynamic.
loader.add_dynamic_predicate(compilation_target, key.0, key.1)?; loader.add_dynamic_predicate(compilation_target, name, arity)?;
loader.incremental_compile_clause( loader.incremental_compile_clause(
key, (name, arity),
asserted_clause, asserted_clause,
compilation_target, compilation_target,
false, false,
@@ -1929,7 +2051,7 @@ impl Machine {
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
loader.compile_clause_clauses( loader.compile_clause_clauses(
key, (name, arity),
compilation_target, compilation_target,
std::iter::once((head, body)), std::iter::once((head, body)),
append_or_prepend, append_or_prepend,
@@ -1940,14 +2062,30 @@ impl Machine {
match compile_assert() { match compile_assert() {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => { Err(SessionError::CompilationError(
let stub = match append_or_prepend { CompilationError::InvalidRuleHead |
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1), CompilationError::InadmissibleFact
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1), )) => {
}; let err = self.machine_st.type_error(
let err = self.machine_st.session_error(e); ValidType::Callable,
self.machine_st.registers[2],
);
Err(self.machine_st.error_form(err, stub)) Err(self.machine_st.error_form(err, stub_gen()))
}
Err(SessionError::CompilationError(
CompilationError::InadmissibleQueryTerm
)) => {
let err = self.machine_st.type_error(
ValidType::Callable,
self.machine_st.registers[3],
);
Err(self.machine_st.error_form(err, stub_gen()))
}
Err(e) => {
let err = self.machine_st.session_error(e);
Err(self.machine_st.error_form(err, stub_gen()))
} }
} }
} }
@@ -2019,10 +2157,10 @@ impl Machine {
.indices .indices
.remove_predicate_skeleton(&compilation_target, &key); .remove_predicate_skeleton(&compilation_target, &key);
let code_index = loader let mut code_index = loader
.get_or_insert_code_index(key, compilation_target); .get_or_insert_code_index(key, compilation_target);
code_index.set(IndexPtr::Undefined); code_index.set(IndexPtr::undefined());
loader.payload.compilation_target = clause_clause_compilation_target; loader.payload.compilation_target = clause_clause_compilation_target;
@@ -2187,7 +2325,7 @@ impl Machine {
let (predicate_name, arity) = self let (predicate_name, arity) = self
.machine_st .machine_st
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); .read_predicate_key(self.machine_st.registers[2], self.machine_st.registers[3]);
let compilation_target = match module_name { let compilation_target = match module_name {
atom!("user") => CompilationTarget::User, atom!("user") => CompilationTarget::User,
@@ -2309,21 +2447,15 @@ impl Machine {
} }
pub(crate) fn builtin_property(&mut self) { pub(crate) fn builtin_property(&mut self) {
let key = self let (name, arity) = self
.machine_st .machine_st
.read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]); .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
match ClauseType::from(key.0, key.1) { if !ClauseType::is_inbuilt(name, arity) { // ClauseType::from(key.0, key.1, &mut self.machine_st.arena) {
ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN(_) => { if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
return; return;
} }
ClauseType::Named(arity, name, _) => {
if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
return;
}
}
_ => {}
} }
self.machine_st.fail = true; self.machine_st.fail = true;
@@ -2355,14 +2487,19 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
#[inline] #[inline]
pub(super) fn load_module( pub(super) fn load_module(
machine_st: &mut MachineState,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
op_dir: &mut OpDir, op_dir: &mut OpDir,
meta_predicate_dir: &mut MetaPredicateDir, meta_predicate_dir: &mut MetaPredicateDir,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
module: &Module, module: &Module,
) { ) {
import_module_exports( let ts = LiveTermStream::new(ListingSource::User);
&mut RetractionInfo::new(0), let payload = LoadStatePayload::new(0, ts);
let mut payload = LiveLoadAndMachineState::new(machine_st, payload);
import_module_exports::<LiveLoadAndMachineState>(
&mut payload,
&compilation_target, &compilation_target,
module, module,
code_dir, code_dir,

View File

@@ -639,10 +639,10 @@ impl CompilationError {
&CompilationError::ExpectedRel => { &CompilationError::ExpectedRel => {
functor!(atom!("expected_relation")) functor!(atom!("expected_relation"))
} }
&CompilationError::InadmissibleFact => { &CompilationError::InadmissibleFact => { // TODO: type_error(callable, _).
functor!(atom!("inadmissible_fact")) functor!(atom!("inadmissible_fact"))
} }
&CompilationError::InadmissibleQueryTerm => { &CompilationError::InadmissibleQueryTerm => { // TODO: type_error(callable, _).
functor!(atom!("inadmissible_query_term")) functor!(atom!("inadmissible_query_term"))
} }
&CompilationError::InconsistentEntry => { &CompilationError::InconsistentEntry => {
@@ -661,7 +661,8 @@ impl CompilationError {
functor!(atom!("no_such_module"), [atom(module_name)]) functor!(atom!("no_such_module"), [atom(module_name)])
} }
&CompilationError::InvalidRuleHead => { &CompilationError::InvalidRuleHead => {
functor!(atom!("invalid_head_of_rule"))
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
} }
&CompilationError::InvalidUseModuleDecl => { &CompilationError::InvalidUseModuleDecl => {
functor!(atom!("invalid_use_module_declaration")) functor!(atom!("invalid_use_module_declaration"))

View File

@@ -4,18 +4,18 @@ use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*;
use crate::machine::loader::*; use crate::machine::loader::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::streams::Stream; use crate::machine::streams::Stream;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
use modular_bitfield::{BitfieldSpecifier, bitfield};
use modular_bitfield::specifiers::*;
use std::cell::Cell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::ops::Deref; use std::ops::{Deref, DerefMut};
use std::rc::Rc; use std::rc::Rc;
use crate::types::*; use crate::types::*;
@@ -59,9 +59,6 @@ impl PartialOrd<Ref> for HeapCellValue {
} }
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
// _ if self.is_ref() => {
// let h1 = self.get_value();
match r.get_tag() { match r.get_tag() {
RefTag::StackCell => Some(Ordering::Less), RefTag::StackCell => Some(Ordering::Less),
_ => { _ => {
@@ -77,52 +74,157 @@ impl PartialOrd<Ref> for HeapCellValue {
} }
} }
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
pub enum IndexPtr { #[bits = 7]
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. pub enum IndexPtrTag {
DynamicIndex(usize), DynamicUndefined = 0b1000101, // a predicate, declared as dynamic, whose location in code is as yet undefined.
Index(usize), DynamicIndex = 0b1000110,
Undefined, Index = 0b1000111,
Undefined = 0b1001000,
} }
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] #[bitfield]
pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>); #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct IndexPtr {
pub p: B56,
#[allow(unused)] m: bool,
pub tag: IndexPtrTag,
}
impl IndexPtr {
#[inline(always)]
pub(crate) fn dynamic_undefined() -> Self {
IndexPtr::new()
.with_p(0)
.with_m(false)
.with_tag(IndexPtrTag::DynamicUndefined)
}
#[inline(always)]
pub(crate) fn undefined() -> Self {
IndexPtr::new()
.with_p(0)
.with_m(false)
.with_tag(IndexPtrTag::Undefined)
}
#[inline(always)]
pub(crate) fn dynamic_index(p: usize) -> Self {
IndexPtr::new()
.with_p(p as u64)
.with_m(false)
.with_tag(IndexPtrTag::DynamicIndex)
}
#[inline(always)]
pub(crate) fn index(p: usize) -> Self {
IndexPtr::new()
.with_p(p as u64)
.with_m(false)
.with_tag(IndexPtrTag::Index)
}
#[inline(always)]
pub(crate) fn is_undefined(&self) -> bool {
match self.tag() {
IndexPtrTag::Undefined => true,
_ => false,
}
}
#[inline(always)]
pub(crate) fn is_dynamic_undefined(&self) -> bool {
match self.tag() {
IndexPtrTag::DynamicUndefined => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(TypedArenaPtr<IndexPtr>);
const_assert!(std::mem::align_of::<CodeIndex>() == 8);
impl Deref for CodeIndex { impl Deref for CodeIndex {
type Target = Cell<IndexPtr>; type Target = TypedArenaPtr<IndexPtr>;
#[inline] #[inline(always)]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &TypedArenaPtr<IndexPtr> {
self.0.deref() &self.0
}
}
impl DerefMut for CodeIndex {
#[inline(always)]
fn deref_mut(&mut self) -> &mut TypedArenaPtr<IndexPtr> {
&mut self.0
}
}
impl From<CodeIndex> for UntypedArenaPtr {
#[inline(always)]
fn from(ptr: CodeIndex) -> UntypedArenaPtr {
unsafe { std::mem::transmute(ptr.0.as_ptr()) }
}
}
impl From<UntypedArenaPtr> for CodeIndex {
#[inline(always)]
fn from(ptr: UntypedArenaPtr) -> CodeIndex {
CodeIndex(TypedArenaPtr::new(ptr.get_ptr() as *mut IndexPtr))
}
}
impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
#[inline(always)]
fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {
CodeIndex(ptr)
} }
} }
impl CodeIndex { impl CodeIndex {
#[inline] #[inline]
pub(super) fn new(ptr: IndexPtr) -> Self { pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
CodeIndex(Rc::new(Cell::new(ptr))) CodeIndex(arena_alloc!(ptr, arena))
} }
#[inline] #[inline(always)]
pub(crate) fn is_undefined(&self) -> bool { pub(crate) fn default(arena: &mut Arena) -> Self {
match self.0.get() { CodeIndex::new(IndexPtr::undefined(), arena)
IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true,
_ => false,
}
} }
pub(crate) fn local(&self) -> Option<usize> { pub(crate) fn local(&self) -> Option<usize> {
match self.0.get() { match self.0.tag() {
IndexPtr::Index(i) => Some(i), IndexPtrTag::Index => Some(self.0.p() as usize),
IndexPtr::DynamicIndex(i) => Some(i), IndexPtrTag::DynamicIndex => Some(self.0.p() as usize),
_ => None, _ => None,
} }
} }
}
impl Default for CodeIndex { #[inline(always)]
fn default() -> Self { pub(crate) fn get(&self) -> IndexPtr {
CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined))) *self.0.deref()
}
#[inline(always)]
pub(crate) fn set(&mut self, value: IndexPtr) {
*self.0.deref_mut() = value;
}
#[inline(always)]
pub(crate) fn get_tag(self) -> IndexPtrTag {
self.0.tag()
}
#[inline(always)]
pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr {
std::mem::replace(self.0.deref_mut(), value)
}
#[inline(always)]
pub(crate) fn as_ptr(&self) -> *const IndexPtr {
self.0.as_ptr()
} }
} }
@@ -269,19 +371,22 @@ impl IndexStore {
module: Atom, module: Atom,
) -> Option<CodeIndex> { ) -> Option<CodeIndex> {
if module == atom!("user") { if module == atom!("user") {
match ClauseType::from(name, arity) { /*match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(), ClauseType::Named(arity, name, _) => */
_ => None, self.code_dir.get(&(name, arity)).cloned()
} /* _ => None,
}*/
} else { } else {
self.modules self.modules
.get(&module) .get(&module)
.and_then(|module| match ClauseType::from(name, arity) { .and_then(|module|/* |module| match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => { ClauseType::Named(arity, name, _) => { */
module.code_dir.get(&(name, arity)).cloned() module.code_dir.get(&(name, arity)).cloned()
/*
} }
_ => None, _ => None,
}) } */
)
} }
} }

View File

@@ -75,6 +75,7 @@ pub struct MachineState {
pub(super) hb: usize, pub(super) hb: usize,
pub(super) block: usize, // an offset into the OR stack. pub(super) block: usize, // an offset into the OR stack.
pub(super) ball: Ball, pub(super) ball: Ball,
pub(super) ball_stack: Vec<Ball>, // save current ball before jumping via, e.g., verify_attr interrupt.
pub(super) lifted_heap: Heap, pub(super) lifted_heap: Heap,
pub(super) interms: Vec<Number>, // intermediate numbers. pub(super) interms: Vec<Number>, // intermediate numbers.
// locations of cleaners, cut points, the previous block. for setup_call_cleanup. // locations of cleaners, cut points, the previous block. for setup_call_cleanup.
@@ -113,6 +114,7 @@ impl fmt::Debug for MachineState {
.field("hb", &self.hb) .field("hb", &self.hb)
.field("block", &self.block) .field("block", &self.block)
.field("ball", &self.ball) .field("ball", &self.ball)
.field("ball_stack", &self.ball_stack)
.field("lifted_heap", &self.lifted_heap) .field("lifted_heap", &self.lifted_heap)
.field("interms", &self.interms) .field("interms", &self.interms)
.field("flags", &self.flags) .field("flags", &self.flags)
@@ -418,6 +420,17 @@ impl MachineState {
} }
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if arity == 0 {
if let Some(c) = name.as_char() {
chars.push(c);
continue;
}
}
}
_ => { _ => {
} }
); );
@@ -454,6 +467,20 @@ impl MachineState {
self.b0 = self.b; self.b0 = self.b;
} }
#[inline(always)]
pub fn neck_cut(&mut self) {
let b = self.b;
let b0 = self.b0;
if b > b0 {
self.b = b0;
if b > self.e {
self.stack.truncate(b);
}
}
}
// Safety: the atom_tbl lives for the lifetime of the machine, as does the helper, so the ptr // Safety: the atom_tbl lives for the lifetime of the machine, as does the helper, so the ptr
// will always be valid. // will always be valid.
pub fn read_term_from_user_input(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { pub fn read_term_from_user_input(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
@@ -511,7 +538,7 @@ impl MachineState {
loop { loop {
match self.read(stream, &indices.op_dir) { match self.read(stream, &indices.op_dir) {
Ok(term_write_result) => { Ok(mut term_write_result) => {
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc], let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
pstr_loc_as_cell!(term_write_result.heap_loc) pstr_loc_as_cell!(term_write_result.heap_loc)
@@ -543,6 +570,10 @@ impl MachineState {
} }
} }
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
let singleton_var_list = push_var_eq_functors( let singleton_var_list = push_var_eq_functors(
&mut self.heap, &mut self.heap,
term_write_result.var_dict.iter().filter(|(_, binding)| { term_write_result.var_dict.iter().filter(|(_, binding)| {
@@ -666,6 +697,13 @@ impl MachineState {
debug_assert_eq!(_arity, 0); debug_assert_eq!(_arity, 0);
var_names.insert(var, Rc::new(name.as_str().to_owned())); var_names.insert(var, Rc::new(name.as_str().to_owned()));
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
var_names.insert(var, Rc::new(name.as_str().to_owned()));
}
_ => { _ => {
unreachable!(); unreachable!();
} }
@@ -677,34 +715,64 @@ impl MachineState {
); );
} }
let ignore_ops = read_heap_cell!(ignore_ops,
(HeapCellValueTag::Atom, (name, _arity)) => {
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let numbervars = read_heap_cell!(numbervars,
(HeapCellValueTag::Atom, (name, _arity)) => {
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let quoted = read_heap_cell!(quoted,
(HeapCellValueTag::Atom, (name, _arity)) => {
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.heap, &mut self.heap,
&mut self.arena,
op_dir, op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
term_to_be_printed, term_to_be_printed,
); );
if let HeapCellValueTag::Atom = ignore_ops.get_tag() { printer.ignore_ops = ignore_ops;
let name = cell_as_atom!(ignore_ops); printer.numbervars = numbervars;
printer.ignore_ops = name == atom!("true"); printer.quoted = quoted;
} else {
unreachable!();
}
if let HeapCellValueTag::Atom = numbervars.get_tag() {
let name = cell_as_atom!(numbervars);
printer.numbervars = name == atom!("true");
} else {
unreachable!();
}
if let HeapCellValueTag::Atom = quoted.get_tag() {
let name = cell_as_atom!(quoted);
printer.quoted = name == atom!("true");
} else {
unreachable!();
}
match Number::try_from(max_depth) { match Number::try_from(max_depth) {
Ok(Number::Fixnum(n)) => { Ok(Number::Fixnum(n)) => {

View File

@@ -47,6 +47,7 @@ impl MachineState {
hb: 0, hb: 0,
block: 0, block: 0,
ball: Ball::new(), ball: Ball::new(),
ball_stack: vec![],
lifted_heap: Heap::new(), lifted_heap: Heap::new(),
interms: vec![Number::default();256], interms: vec![Number::default();256],
cont_pts: Vec::with_capacity(256), cont_pts: Vec::with_capacity(256),
@@ -347,10 +348,27 @@ impl MachineState {
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
self.fail = cstr_atom != atom!("[]"); self.fail = cstr_atom != atom!("[]");
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if arity == 0 {
self.fail = atom == atom!("") && name != atom!("[]");
} else {
// this is intentionally the same policy for
// value.tag() == Lis and PStrLoc. they're not
// grouped together to allow for arity == 0.
self.unify_partial_string(atom_as_cstr_cell!(atom), value);
if !self.pdl.is_empty() {
self.unify();
}
}
}
(HeapCellValueTag::CStr, cstr_atom) => { (HeapCellValueTag::CStr, cstr_atom) => {
self.fail = atom != cstr_atom; self.fail = atom != cstr_atom;
} }
(HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
self.unify_partial_string(atom_as_cstr_cell!(atom), value); self.unify_partial_string(atom_as_cstr_cell!(atom), value);
if !self.pdl.is_empty() { if !self.pdl.is_empty() {
@@ -553,6 +571,12 @@ impl MachineState {
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
self.fail = !(arity == 0 && name == atom); self.fail = !(arity == 0 && name == atom);
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
self.fail = !(arity == 0 && name == atom);
}
(HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => { (HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => {
self.fail = cstr_atom != atom!(""); self.fail = cstr_atom != atom!("");
} }
@@ -587,6 +611,16 @@ impl MachineState {
self.fail = true; self.fail = true;
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if let Some(c2) = name.as_char() {
self.fail = !(c == c2 && arity == 0);
} else {
self.fail = true;
}
}
(HeapCellValueTag::Char, c2) => { (HeapCellValueTag::Char, c2) => {
if c != c2 { if c != c2 {
self.fail = true; self.fail = true;
@@ -739,11 +773,6 @@ impl MachineState {
self.unify_atom(name, d2); self.unify_atom(name, d2);
} }
(HeapCellValueTag::Str, s1) => { (HeapCellValueTag::Str, s1) => {
if d2.is_constant() {
self.fail = true;
break;
}
if tabu_list.contains(&(d1, d2)) { if tabu_list.contains(&(d1, d2)) {
continue; continue;
} }
@@ -969,9 +998,7 @@ impl MachineState {
} }
} }
(HeapCellValueTag::Atom, (n2, a2)) => { (HeapCellValueTag::Atom, (n2, a2)) => {
if !(a1 == 0 && a2 == 0 && n1 == n2) { self.fail = !(a1 == 0 && a2 == 0 && n1 == n2);
self.fail = true;
}
} }
(HeapCellValueTag::AttrVar, h) => { (HeapCellValueTag::AttrVar, h) => {
if self.bind_with_occurs_check(Ref::attr_var(h), str_loc_as_cell!(s1)) { if self.bind_with_occurs_check(Ref::attr_var(h), str_loc_as_cell!(s1)) {
@@ -1285,11 +1312,6 @@ impl MachineState {
self.unify_atom(name, d2); self.unify_atom(name, d2);
} }
(HeapCellValueTag::Str, s1) => { (HeapCellValueTag::Str, s1) => {
if d2.is_constant() {
self.fail = true;
break;
}
if tabu_list.contains(&(d1, d2)) { if tabu_list.contains(&(d1, d2)) {
continue; continue;
} }
@@ -1492,8 +1514,8 @@ impl MachineState {
let v1 = self.store(s1); let v1 = self.store(s1);
let v2 = self.store(s2); let v2 = self.store(s2);
let order_cat_v1 = v1.order_category(); let order_cat_v1 = v1.order_category(&self.heap);
let order_cat_v2 = v2.order_category(); let order_cat_v2 = v2.order_category(&self.heap);
if order_cat_v1 != order_cat_v2 { if order_cat_v1 != order_cat_v2 {
self.pdl.clear(); self.pdl.clear();
@@ -1552,6 +1574,15 @@ impl MachineState {
); );
} }
} }
(HeapCellValueTag::Str, s) => {
let n2 = cell_as_atom_cell!(self.heap[s])
.get_name();
if n1 != n2 {
self.pdl.clear();
return Some(n1.cmp(&n2));
}
}
_ => { _ => {
unreachable!(); unreachable!();
} }
@@ -1579,11 +1610,67 @@ impl MachineState {
return Some(c1.cmp(&c2)); return Some(c1.cmp(&c2));
} }
} }
(HeapCellValueTag::Str, s) => {
let n2 = cell_as_atom_cell!(self.heap[s])
.get_name();
if let Some(c2) = n2.as_char() {
if c1 != c2 {
self.pdl.clear();
return Some(c1.cmp(&c2));
}
} else {
self.pdl.clear();
return Some(
Some(c1).cmp(&n2.chars().next())
.then(Ordering::Less)
);
}
}
_ => { _ => {
unreachable!() unreachable!()
} }
) )
} }
(HeapCellValueTag::Str, s) => {
let n1 = cell_as_atom_cell!(self.heap[s])
.get_name();
read_heap_cell!(v2,
(HeapCellValueTag::Atom, (n2, _a2)) => {
if n1 != n2 {
self.pdl.clear();
return Some(n1.cmp(&n2));
}
}
(HeapCellValueTag::Char, c2) => {
if let Some(c1) = n1.as_char() {
if c1 != c2 {
self.pdl.clear();
return Some(c1.cmp(&c2));
}
} else {
self.pdl.clear();
return Some(
n1.chars().next().cmp(&Some(c2))
.then(Ordering::Greater)
);
}
}
(HeapCellValueTag::Str, s) => {
let n2 = cell_as_atom_cell!(self.heap[s])
.get_name();
if n1 != n2 {
self.pdl.clear();
return Some(n1.cmp(&n2));
}
}
_ => {
unreachable!();
}
)
}
_ => { _ => {
unreachable!() unreachable!()
} }
@@ -1597,8 +1684,8 @@ impl MachineState {
) -> Option<Ordering> { ) -> Option<Ordering> {
let compound = Some(TermOrderCategory::Compound); let compound = Some(TermOrderCategory::Compound);
if iter2.focus.order_category() != compound { if iter2.focus.order_category(iter2.heap) != compound {
Some(compound.cmp(&iter2.focus.order_category())) Some(compound.cmp(&iter2.focus.order_category(iter2.heap)))
} else { } else {
let c1 = match iteratee { let c1 = match iteratee {
PStrIteratee::Char(_, c) => c, PStrIteratee::Char(_, c) => c,
@@ -2116,7 +2203,7 @@ impl MachineState {
heap_bound_deref(iter.heap, value), heap_bound_deref(iter.heap, value),
)); ));
if value.is_compound() { if value.is_compound(iter.heap) {
return true; return true;
} }
} }
@@ -2403,6 +2490,21 @@ impl MachineState {
a1.as_var().unwrap(), a1.as_var().unwrap(),
); );
} }
(HeapCellValueTag::Str, s) => {
let (name, atom_arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if atom_arity == 0 {
self.try_functor_fabricate_struct(
name,
arity as usize,
a1.as_var().unwrap(),
);
} else {
let err = self.type_error(ValidType::Atomic, store_name);
return Err(self.error_form(err, stub_gen()));
}
}
(HeapCellValueTag::Char, c) => { (HeapCellValueTag::Char, c) => {
let c = self.atom_tbl.build_with(&c.to_string()); let c = self.atom_tbl.build_with(&c.to_string());
@@ -2444,6 +2546,17 @@ impl MachineState {
let err = self.instantiation_error(); let err = self.instantiation_error();
Err(self.error_form(err, stub_gen())) Err(self.error_form(err, stub_gen()))
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if name == atom!("[]") && arity == 0 {
Ok(vec![])
} else {
let err = self.type_error(ValidType::List, value);
Err(self.error_form(err, stub_gen()))
}
}
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
if name == atom!("[]") && arity == 0 { if name == atom!("[]") && arity == 0 {
Ok(vec![]) Ok(vec![])
@@ -2484,6 +2597,17 @@ impl MachineState {
(HeapCellValueTag::PStrLoc, l) => { (HeapCellValueTag::PStrLoc, l) => {
return self.try_from_partial_string(result, l, stub_gen, a1); return self.try_from_partial_string(result, l, stub_gen, a1);
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if name == atom!("[]") && arity == 0 {
break;
} else {
let err = self.type_error(ValidType::List, a1);
return Err(self.error_form(err, stub_gen()));
}
}
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
if name == atom!("[]") && arity == 0 { if name == atom!("[]") && arity == 0 {
break; break;

View File

@@ -61,7 +61,6 @@ impl MockWAM {
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.machine_st.heap, &mut self.machine_st.heap,
&mut self.machine_st.arena,
&self.op_dir, &self.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(term_write_result.heap_loc), heap_loc_as_cell!(term_write_result.heap_loc),
@@ -272,6 +271,7 @@ impl Machine {
if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) { if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,
@@ -297,6 +297,7 @@ impl Machine {
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,

View File

@@ -22,6 +22,7 @@ pub mod streams;
pub mod system_calls; pub mod system_calls;
pub mod term_stream; pub mod term_stream;
use crate::arena::*;
use crate::arithmetic::*; use crate::arithmetic::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
@@ -160,6 +161,24 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
} }
} }
#[inline]
pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
read_heap_cell!(value,
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::IndexPtr, ip) => {
return Some(CodeIndex::from(ip));
}
_ => {}
);
}
_ => {
}
);
None
}
impl Machine { impl Machine {
#[inline] #[inline]
pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) { pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
@@ -220,6 +239,7 @@ impl Machine {
if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) { if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) {
load_module( load_module(
&mut self.machine_st,
&mut self.indices.code_dir, &mut self.indices.code_dir,
&mut self.indices.op_dir, &mut self.indices.op_dir,
&mut self.indices.meta_predicates, &mut self.indices.meta_predicates,
@@ -287,7 +307,7 @@ impl Machine {
} }
pub(crate) fn configure_modules(&mut self) { pub(crate) fn configure_modules(&mut self) {
fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) { fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir, arena: &mut Arena) {
for arity in 1..66 { for arity in 1..66 {
let key = (atom!("call"), arity); let key = (atom!("call"), arity);
@@ -295,7 +315,7 @@ impl Machine {
Some(src_code_index) => { Some(src_code_index) => {
let target_code_index = target_code_dir let target_code_index = target_code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)); .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
target_code_index.set(src_code_index.get()); target_code_index.set(src_code_index.get());
} }
@@ -311,6 +331,7 @@ impl Machine {
// Import loader's exports into the builtins module so they will be // Import loader's exports into the builtins module so they will be
// implicitly included in every further module. // implicitly included in every further module.
load_module( load_module(
&mut self.machine_st,
&mut builtins.code_dir, &mut builtins.code_dir,
&mut builtins.op_dir, &mut builtins.op_dir,
&mut builtins.meta_predicates, &mut builtins.meta_predicates,
@@ -331,10 +352,10 @@ impl Machine {
} }
for (_, target_module) in self.indices.modules.iter_mut() { for (_, target_module) in self.indices.modules.iter_mut() {
update_call_n_indices(&loader, &mut target_module.code_dir); update_call_n_indices(&loader, &mut target_module.code_dir, &mut self.machine_st.arena);
} }
update_call_n_indices(&loader, &mut self.indices.code_dir); update_call_n_indices(&loader, &mut self.indices.code_dir, &mut self.machine_st.arena);
self.indices.modules.insert(atom!("loader"), loader); self.indices.modules.insert(atom!("loader"), loader);
} else { } else {
@@ -393,7 +414,10 @@ impl Machine {
for (p, instr) in self.code[impls_offset ..].iter().enumerate() { for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
let key = instr.to_name_and_arity(); let key = instr.to_name_and_arity();
self.indices.code_dir.insert(key, CodeIndex::new(IndexPtr::Index(p + impls_offset))); self.indices.code_dir.insert(
key,
CodeIndex::new(IndexPtr::index(p + impls_offset), &mut self.machine_st.arena),
);
} }
} }
@@ -407,9 +431,7 @@ impl Machine {
let user_output = Stream::stdout(&mut machine_st.arena); let user_output = Stream::stdout(&mut machine_st.arena);
let user_error = Stream::stderr(&mut machine_st.arena); let user_error = Stream::stderr(&mut machine_st.arena);
let runtime = tokio::runtime::Builder::new_current_thread() let runtime = tokio::runtime::Runtime::new()
.enable_all()
.build()
.unwrap(); .unwrap();
let mut wam = Machine { let mut wam = Machine {
@@ -455,6 +477,7 @@ impl Machine {
if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) { if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,
@@ -480,6 +503,7 @@ impl Machine {
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,
@@ -666,18 +690,20 @@ impl Machine {
#[inline(always)] #[inline(always)]
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
match idx { let compiled_tl_index = idx.p() as usize;
IndexPtr::DynamicUndefined => {
match idx.tag() {
IndexPtrTag::DynamicUndefined => {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
IndexPtr::Undefined => { IndexPtrTag::Undefined => {
return Err(self.machine_st.throw_undefined_error(name, arity)); return Err(self.machine_st.throw_undefined_error(name, arity));
} }
IndexPtr::DynamicIndex(compiled_tl_index) => { IndexPtrTag::DynamicIndex => {
self.machine_st.dynamic_mode = FirstOrNext::First; self.machine_st.dynamic_mode = FirstOrNext::First;
self.machine_st.call_at_index(arity, compiled_tl_index); self.machine_st.call_at_index(arity, compiled_tl_index);
} }
IndexPtr::Index(compiled_tl_index) => { IndexPtrTag::Index => {
self.machine_st.call_at_index(arity, compiled_tl_index); self.machine_st.call_at_index(arity, compiled_tl_index);
} }
} }
@@ -687,18 +713,20 @@ impl Machine {
#[inline(always)] #[inline(always)]
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
match idx { let compiled_tl_index = idx.p() as usize;
IndexPtr::DynamicUndefined => {
match idx.tag() {
IndexPtrTag::DynamicUndefined => {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
IndexPtr::Undefined => { IndexPtrTag::Undefined => {
return Err(self.machine_st.throw_undefined_error(name, arity)); return Err(self.machine_st.throw_undefined_error(name, arity));
} }
IndexPtr::DynamicIndex(compiled_tl_index) => { IndexPtrTag::DynamicIndex => {
self.machine_st.dynamic_mode = FirstOrNext::First; self.machine_st.dynamic_mode = FirstOrNext::First;
self.machine_st.execute_at_index(arity, compiled_tl_index); self.machine_st.execute_at_index(arity, compiled_tl_index);
} }
IndexPtr::Index(compiled_tl_index) => { IndexPtrTag::Index => {
self.machine_st.execute_at_index(arity, compiled_tl_index) self.machine_st.execute_at_index(arity, compiled_tl_index)
} }
} }

View File

@@ -179,6 +179,14 @@ impl<'a> HeapPStrIter<'a> {
if self.at_string_terminator() { if self.at_string_terminator() {
self.focus = empty_list_as_cell!(); self.focus = empty_list_as_cell!();
self.brent_st.hare = result.focus; self.brent_st.hare = result.focus;
} else {
read_heap_cell!(self.heap[result.focus],
(HeapCellValueTag::Lis | HeapCellValueTag::Str) => {
self.focus = self.heap[self.brent_st.hare];
}
_ => {
}
);
} }
} }
@@ -330,7 +338,7 @@ impl<'a> HeapPStrIter<'a> {
}) })
} else { } else {
None None
} };
} }
(HeapCellValueTag::Str, s) => { (HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s]) let (name, arity) = cell_as_atom_cell!(self.heap[s])

View File

@@ -470,14 +470,141 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
} }
} }
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
module_name: Atom,
terms: Vec<Term>,
meta_specs: Vec<MetaSpec>,
) -> Vec<Term> {
let mut arg_terms = Vec::with_capacity(terms.len());
for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
if let Some(name) = term.name() {
if name == atom!("$call") {
arg_terms.push(term);
continue;
}
let arity = term.arity();
fn get_qualified_name(
module_term: &Term,
qualified_term: &Term,
) -> Option<(Atom, Atom)> {
if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
if let Some(name) = qualified_term.name() {
return Some((*module_name, name));
}
}
None
}
fn identity_fn(_module_name: Atom, term: Term) -> Term {
term
}
fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
Term::Clause(Cell::default(), atom!(":"), vec![
Term::Literal(Cell::default(), Literal::Atom(module_name)),
term
])
}
let process_term: fn(Atom, Term) -> Term;
let (module_name, key, term) = match term {
Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1]) {
process_term = tag_with_module_name;
(module_name, (name, terms[1].arity() + supp_args), terms.pop().unwrap())
} else {
arg_terms.push(Term::Clause(cell, atom!(":"), terms));
continue;
}
}
term => {
process_term = identity_fn;
(module_name, (name, arity + supp_args), term)
}
};
let term = match term {
Term::Clause(cell, name, mut terms) => {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
arg_terms.push(process_term(
module_name,
Term::Clause(cell, name, terms),
));
continue;
}
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
process_term(module_name, Term::Clause(cell, name, terms))
}
Term::Literal(cell, Literal::Atom(name)) => {
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
process_term(module_name, Term::Clause(
cell,
name,
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
))
}
term => term,
};
arg_terms.push(term);
continue;
}
}
arg_terms.push(term);
}
arg_terms
}
#[inline] #[inline]
fn clause_to_query_term<'a, LS: LoadState<'a>>( fn clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
name: Atom, name: Atom,
terms: Vec<Term>, mut terms: Vec<Term>,
call_policy: CallPolicy, call_policy: CallPolicy,
) -> QueryTerm { ) -> QueryTerm {
let ct = loader.get_clause_type(name, terms.len()); if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
// supplementary code vector indices are unnecessary for
// root-level clauses.
terms.pop();
}
let mut ct = loader.get_clause_type(name, terms.len());
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let module_name = loader.payload.compilation_target.module_name();
let terms = build_meta_predicate_clause(
loader,
module_name,
terms,
meta_specs,
);
return QueryTerm::Clause(
Cell::default(),
ClauseType::Named(arity, name, idx),
terms,
call_policy,
);
}
ct = ClauseType::Named(arity, name, idx);
}
QueryTerm::Clause(Cell::default(), ct, terms, call_policy) QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
} }
@@ -486,13 +613,120 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
module_name: Atom, module_name: Atom,
name: Atom, name: Atom,
terms: Vec<Term>, mut terms: Vec<Term>,
call_policy: CallPolicy, call_policy: CallPolicy,
) -> QueryTerm { ) -> QueryTerm {
let ct = loader.get_qualified_clause_type(module_name, name, terms.len()); if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
// supplementary code vector indices are unnecessary for
// root-level clauses.
terms.pop();
}
let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let terms = build_meta_predicate_clause(
loader,
module_name,
terms,
meta_specs,
);
return QueryTerm::Clause(
Cell::default(),
ClauseType::Named(arity, name, idx),
terms,
call_policy,
);
}
ct = ClauseType::Named(arity, name, idx);
}
QueryTerm::Clause(Cell::default(), ct, terms, call_policy) QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
} }
fn compute_head(term: &Term) -> Vec<Term> {
let mut vars = IndexSet::new();
for term in post_order_iter(term) {
if let TermRef::Var(_, _, v) = term {
vars.insert(v.clone());
}
}
vars.insert(Rc::new(String::from("!")));
vars.into_iter()
.map(|v| Term::Var(Cell::default(), v))
.collect()
}
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule)
}
// the terms form the body of the rule. We create a head, by
// gathering variables from the body of terms and recording them
// in the head clause.
fn build_rule(body_term: Term) -> (JumpStub, VecDeque<Term>) {
// collect the vars of body_term into a head, return the num_vars
// (the arity) as well.
let vars = compute_head(&body_term);
let rule = build_rule_body(&vars, body_term);
(vars, VecDeque::from(vec![rule]))
}
fn build_disjunct(body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = compute_head(&body_term);
let results = unfold_by_str(body_term, atom!(";"))
.into_iter()
.map(|term| {
let mut subterms = unfold_by_str(term, atom!(","));
mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
build_rule_body(&vars, clause)
})
.collect();
(vars, results)
}
fn build_if_then(prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, atom!(","));
let comma_sym = atom!(",");
let cut_sym = Literal::Atom(atom!("!"));
prec_seq.push(Term::Literal(Cell::default(), cut_sym));
mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
let mut conq_seq = unfold_by_str(conq, atom!(","));
mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter());
let back_term = prec_seq.pop().unwrap();
let front_term = prec_seq.pop().unwrap();
let body_term = Term::Clause(
Cell::default(),
comma_sym,
vec![front_term, back_term],
);
build_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Preprocessor { pub(crate) struct Preprocessor {
queue: VecDeque<VecDeque<Term>>, queue: VecDeque<VecDeque<Term>>,
@@ -514,86 +748,6 @@ impl Preprocessor {
} }
} }
fn compute_head(&self, term: &Term) -> Vec<Term> {
let mut vars = IndexSet::new();
for term in post_order_iter(term) {
if let TermRef::Var(_, _, v) = term {
vars.insert(v.clone());
}
}
vars.insert(Rc::new(String::from("!")));
vars.into_iter()
.map(|v| Term::Var(Cell::default(), v))
.collect()
}
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone());
let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule)
}
// the terms form the body of the rule. We create a head, by
// gathering variables from the body of terms and recording them
// in the head clause.
fn fabricate_rule(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
// collect the vars of body_term into a head, return the num_vars
// (the arity) as well.
let vars = self.compute_head(&body_term);
let rule = self.fabricate_rule_body(&vars, body_term);
(vars, VecDeque::from(vec![rule]))
}
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = self.compute_head(&body_term);
let results = unfold_by_str(body_term, atom!(";"))
.into_iter()
.map(|term| {
let mut subterms = unfold_by_str(term, atom!(","));
mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
self.fabricate_rule_body(&vars, clause)
})
.collect();
(vars, results)
}
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, atom!(","));
let comma_sym = atom!(",");
let cut_sym = Literal::Atom(atom!("!"));
prec_seq.push(Term::Literal(Cell::default(), cut_sym));
mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
let mut conq_seq = unfold_by_str(conq, atom!(","));
mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter());
let back_term = prec_seq.pop().unwrap();
let front_term = prec_seq.pop().unwrap();
let body_term = Term::Clause(
Cell::default(),
comma_sym,
vec![front_term, back_term],
);
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
fn to_query_term<'a, LS: LoadState<'a>>( fn to_query_term<'a, LS: LoadState<'a>>(
&mut self, &mut self,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
@@ -605,7 +759,9 @@ impl Preprocessor {
Ok(QueryTerm::BlockedCut) Ok(QueryTerm::BlockedCut)
} else { } else {
Ok(clause_to_query_term( Ok(clause_to_query_term(
loader, name, vec![], loader,
name,
vec![],
self.settings.default_call_policy(), self.settings.default_call_policy(),
)) ))
} }
@@ -618,7 +774,7 @@ impl Preprocessor {
(atom!(";"), 2) => { (atom!(";"), 2) => {
let term = Term::Clause(r, name, terms); let term = Term::Clause(r, name, terms);
let (stub, clauses) = self.fabricate_disjunct(term); let (stub, clauses) = build_disjunct(term);
self.queue.push_back(clauses); self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
@@ -627,7 +783,7 @@ impl Preprocessor {
let conq = terms.pop().unwrap(); let conq = terms.pop().unwrap();
let prec = terms.pop().unwrap(); let prec = terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq); let (stub, clauses) = build_if_then(prec, conq);
self.queue.push_back(clauses); self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
@@ -644,7 +800,7 @@ impl Preprocessor {
let terms = vec![prec, conq]; let terms = vec![prec, conq];
let term = Term::Clause(Cell::default(), atom!(";"), terms); let term = Term::Clause(Cell::default(), atom!(";"), terms);
let (stub, clauses) = self.fabricate_disjunct(term); let (stub, clauses) = build_disjunct(term);
debug_assert!(clauses.len() > 0); debug_assert!(clauses.len() > 0);
self.queue.push_back(clauses); self.queue.push_back(clauses);
@@ -689,8 +845,8 @@ impl Preprocessor {
Ok(clause_to_query_term( Ok(clause_to_query_term(
loader, loader,
name, atom!("call"),
terms, vec![Term::Clause(r, name, terms)],
self.settings.default_call_policy(), self.settings.default_call_policy(),
)) ))
} }

View File

@@ -26,6 +26,7 @@ use std::ops::{Deref, DerefMut};
use std::ptr; use std::ptr;
use native_tls::TlsStream; use native_tls::TlsStream;
use hyper::body::{Bytes, Sender};
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
#[bits = 1] #[bits = 1]
@@ -249,24 +250,51 @@ impl Write for NamedTlsStream {
} }
} }
pub struct NamedHttpClientStream { pub struct HttpReadStream {
url: Atom, url: Atom,
body_reader: Box<dyn BufRead>, body_reader: Box<dyn BufRead>,
} }
impl Debug for NamedHttpClientStream { impl Debug for HttpReadStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Http Client Stream [{}]", self.url.as_str()) write!(f, "Http Read Stream [{}]", self.url.as_str())
} }
} }
impl Read for NamedHttpClientStream { impl Read for HttpReadStream {
#[inline] #[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.body_reader.read(buf) self.body_reader.read(buf)
} }
} }
pub struct HttpWriteStream {
body_writer: Sender,
}
impl Debug for HttpWriteStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Http Write Stream")
}
}
impl Write for HttpWriteStream {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let bytes = Bytes::copy_from_slice(buf);
let len = bytes.len();
match self.body_writer.try_send_data(bytes) {
Ok(()) => Ok(len),
Err(_) => Err(std::io::Error::from(ErrorKind::Interrupted))
}
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct StandardOutputStream {} pub struct StandardOutputStream {}
@@ -405,7 +433,8 @@ arena_allocated_impl_for_stream!(CharReader<InputFileStream>, InputFileStream);
arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream); arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream);
arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream); arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream);
arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream); arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream);
arena_allocated_impl_for_stream!(CharReader<NamedHttpClientStream>, NamedHttpClientStream); arena_allocated_impl_for_stream!(CharReader<HttpReadStream>, HttpReadStream);
arena_allocated_impl_for_stream!(CharReader<HttpWriteStream>, HttpWriteStream);
arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream); arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream);
arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream); arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream);
arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream); arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
@@ -419,7 +448,8 @@ pub enum Stream {
StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>), StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>), NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>), NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
NamedHttpClient(TypedArenaPtr<StreamLayout<CharReader<NamedHttpClientStream>>>), HttpRead(TypedArenaPtr<StreamLayout<CharReader<HttpReadStream>>>),
HttpWrite(TypedArenaPtr<StreamLayout<CharReader<HttpWriteStream>>>),
Null(StreamOptions), Null(StreamOptions),
Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>), Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>), StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>),
@@ -474,7 +504,8 @@ impl Stream {
} }
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::NamedHttpClientStream => Stream::NamedHttpClient(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::HttpReadStream => Stream::HttpRead(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::HttpWriteStream => Stream::HttpWrite(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::StaticStringStream => { ArenaHeaderTag::StaticStringStream => {
Stream::StaticString(TypedArenaPtr::new(ptr as *mut _)) Stream::StaticString(TypedArenaPtr::new(ptr as *mut _))
@@ -527,7 +558,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.header_ptr(), Stream::StaticString(ptr) => ptr.header_ptr(),
Stream::NamedTcp(ptr) => ptr.header_ptr(), Stream::NamedTcp(ptr) => ptr.header_ptr(),
Stream::NamedTls(ptr) => ptr.header_ptr(), Stream::NamedTls(ptr) => ptr.header_ptr(),
Stream::NamedHttpClient(ptr) => ptr.header_ptr(), Stream::HttpRead(ptr) => ptr.header_ptr(),
Stream::HttpWrite(ptr) => ptr.header_ptr(),
Stream::Null(_) => ptr::null(), Stream::Null(_) => ptr::null(),
Stream::Readline(ptr) => ptr.header_ptr(), Stream::Readline(ptr) => ptr.header_ptr(),
Stream::StandardOutput(ptr) => ptr.header_ptr(), Stream::StandardOutput(ptr) => ptr.header_ptr(),
@@ -543,7 +575,8 @@ impl Stream {
Stream::StaticString(ref ptr) => &ptr.options, Stream::StaticString(ref ptr) => &ptr.options,
Stream::NamedTcp(ref ptr) => &ptr.options, Stream::NamedTcp(ref ptr) => &ptr.options,
Stream::NamedTls(ref ptr) => &ptr.options, Stream::NamedTls(ref ptr) => &ptr.options,
Stream::NamedHttpClient(ref ptr) => &ptr.options, Stream::HttpRead(ref ptr) => &ptr.options,
Stream::HttpWrite(ref ptr) => &ptr.options,
Stream::Null(ref options) => options, Stream::Null(ref options) => options,
Stream::Readline(ref ptr) => &ptr.options, Stream::Readline(ref ptr) => &ptr.options,
Stream::StandardOutput(ref ptr) => &ptr.options, Stream::StandardOutput(ref ptr) => &ptr.options,
@@ -559,7 +592,8 @@ impl Stream {
Stream::StaticString(ref mut ptr) => &mut ptr.options, Stream::StaticString(ref mut ptr) => &mut ptr.options,
Stream::NamedTcp(ref mut ptr) => &mut ptr.options, Stream::NamedTcp(ref mut ptr) => &mut ptr.options,
Stream::NamedTls(ref mut ptr) => &mut ptr.options, Stream::NamedTls(ref mut ptr) => &mut ptr.options,
Stream::NamedHttpClient(ref mut ptr) => &mut ptr.options, Stream::HttpRead(ref mut ptr) => &mut ptr.options,
Stream::HttpWrite(ref mut ptr) => &mut ptr.options,
Stream::Null(ref mut options) => options, Stream::Null(ref mut options) => options,
Stream::Readline(ref mut ptr) => &mut ptr.options, Stream::Readline(ref mut ptr) => &mut ptr.options,
Stream::StandardOutput(ref mut ptr) => &mut ptr.options, Stream::StandardOutput(ref mut ptr) => &mut ptr.options,
@@ -576,7 +610,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read, Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read, Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read, Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::NamedHttpClient(ptr) => ptr.lines_read += incr_num_lines_read, Stream::HttpRead(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::HttpWrite(_) => {}
Stream::Null(_) => {} Stream::Null(_) => {}
Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read, Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read, Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read,
@@ -593,7 +628,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.lines_read = value, Stream::StaticString(ptr) => ptr.lines_read = value,
Stream::NamedTcp(ptr) => ptr.lines_read = value, Stream::NamedTcp(ptr) => ptr.lines_read = value,
Stream::NamedTls(ptr) => ptr.lines_read = value, Stream::NamedTls(ptr) => ptr.lines_read = value,
Stream::NamedHttpClient(ptr) => ptr.lines_read = value, Stream::HttpRead(ptr) => ptr.lines_read = value,
Stream::HttpWrite(_) => {}
Stream::Null(_) => {} Stream::Null(_) => {}
Stream::Readline(ptr) => ptr.lines_read = value, Stream::Readline(ptr) => ptr.lines_read = value,
Stream::StandardOutput(ptr) => ptr.lines_read = value, Stream::StandardOutput(ptr) => ptr.lines_read = value,
@@ -610,7 +646,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.lines_read, Stream::StaticString(ptr) => ptr.lines_read,
Stream::NamedTcp(ptr) => ptr.lines_read, Stream::NamedTcp(ptr) => ptr.lines_read,
Stream::NamedTls(ptr) => ptr.lines_read, Stream::NamedTls(ptr) => ptr.lines_read,
Stream::NamedHttpClient(ptr) => ptr.lines_read, Stream::HttpRead(ptr) => ptr.lines_read,
Stream::HttpWrite(_) => 0,
Stream::Null(_) => 0, Stream::Null(_) => 0,
Stream::Readline(ptr) => ptr.lines_read, Stream::Readline(ptr) => ptr.lines_read,
Stream::StandardOutput(ptr) => ptr.lines_read, Stream::StandardOutput(ptr) => ptr.lines_read,
@@ -625,13 +662,14 @@ impl CharRead for Stream {
Stream::InputFile(file) => (*file).peek_char(), Stream::InputFile(file) => (*file).peek_char(),
Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(), Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(),
Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(), Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(),
Stream::NamedHttpClient(http_stream) => (*http_stream).peek_char(), Stream::HttpRead(http_stream) => (*http_stream).peek_char(),
Stream::Readline(rl_stream) => (*rl_stream).peek_char(), Stream::Readline(rl_stream) => (*rl_stream).peek_char(),
Stream::StaticString(src) => (*src).peek_char(), Stream::StaticString(src) => (*src).peek_char(),
Stream::Byte(cursor) => (*cursor).peek_char(), Stream::Byte(cursor) => (*cursor).peek_char(),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => Some(Err(std::io::Error::new( Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
@@ -644,13 +682,14 @@ impl CharRead for Stream {
Stream::InputFile(file) => (*file).read_char(), Stream::InputFile(file) => (*file).read_char(),
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(), Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(),
Stream::NamedTls(tls_stream) => (*tls_stream).read_char(), Stream::NamedTls(tls_stream) => (*tls_stream).read_char(),
Stream::NamedHttpClient(http_stream) => (*http_stream).read_char(), Stream::HttpRead(http_stream) => (*http_stream).read_char(),
Stream::Readline(rl_stream) => (*rl_stream).read_char(), Stream::Readline(rl_stream) => (*rl_stream).read_char(),
Stream::StaticString(src) => (*src).read_char(), Stream::StaticString(src) => (*src).read_char(),
Stream::Byte(cursor) => (*cursor).read_char(), Stream::Byte(cursor) => (*cursor).read_char(),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => Some(Err(std::io::Error::new( Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
@@ -663,13 +702,14 @@ impl CharRead for Stream {
Stream::InputFile(file) => file.put_back_char(c), Stream::InputFile(file) => file.put_back_char(c),
Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c), Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c),
Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c), Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c),
Stream::NamedHttpClient(http_stream) => http_stream.put_back_char(c), Stream::HttpRead(http_stream) => http_stream.put_back_char(c),
Stream::Readline(rl_stream) => rl_stream.put_back_char(c), Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
Stream::StaticString(src) => src.put_back_char(c), Stream::StaticString(src) => src.put_back_char(c),
Stream::Byte(cursor) => cursor.put_back_char(c), Stream::Byte(cursor) => cursor.put_back_char(c),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => {} Stream::Null(_) => {}
} }
} }
@@ -679,13 +719,14 @@ impl CharRead for Stream {
Stream::InputFile(ref mut file) => file.consume(nread), Stream::InputFile(ref mut file) => file.consume(nread),
Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread), Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread),
Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread), Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread),
Stream::NamedHttpClient(ref mut http_stream) => http_stream.consume(nread), Stream::HttpRead(ref mut http_stream) => http_stream.consume(nread),
Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread), Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread),
Stream::StaticString(ref mut src) => src.consume(nread), Stream::StaticString(ref mut src) => src.consume(nread),
Stream::Byte(ref mut cursor) => cursor.consume(nread), Stream::Byte(ref mut cursor) => cursor.consume(nread),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => {} Stream::Null(_) => {}
} }
} }
@@ -698,13 +739,14 @@ impl Read for Stream {
Stream::InputFile(file) => (*file).read(buf), Stream::InputFile(file) => (*file).read(buf),
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf), Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf),
Stream::NamedTls(tls_stream) => (*tls_stream).read(buf), Stream::NamedTls(tls_stream) => (*tls_stream).read(buf),
Stream::NamedHttpClient(http_stream) => (*http_stream).read(buf), Stream::HttpRead(http_stream) => (*http_stream).read(buf),
Stream::Readline(rl_stream) => (*rl_stream).read(buf), Stream::Readline(rl_stream) => (*rl_stream).read(buf),
Stream::StaticString(src) => (*src).read(buf), Stream::StaticString(src) => (*src).read(buf),
Stream::Byte(cursor) => (*cursor).read(buf), Stream::Byte(cursor) => (*cursor).read(buf),
Stream::OutputFile(_) Stream::OutputFile(_)
| Stream::StandardError(_) | Stream::StandardError(_)
| Stream::StandardOutput(_) | Stream::StandardOutput(_)
| Stream::HttpWrite(_)
| Stream::Null(_) => Err(std::io::Error::new( | Stream::Null(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
@@ -724,7 +766,8 @@ impl Write for Stream {
Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf), Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
Stream::StandardOutput(stream) => stream.write(buf), Stream::StandardOutput(stream) => stream.write(buf),
Stream::StandardError(stream) => stream.write(buf), Stream::StandardError(stream) => stream.write(buf),
Stream::NamedHttpClient(_) | Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
Stream::HttpRead(_) |
Stream::StaticString(_) | Stream::StaticString(_) |
Stream::Readline(_) | Stream::Readline(_) |
Stream::InputFile(..) | Stream::InputFile(..) |
@@ -743,7 +786,8 @@ impl Write for Stream {
Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(), Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
Stream::StandardError(stream) => stream.stream.flush(), Stream::StandardError(stream) => stream.stream.flush(),
Stream::StandardOutput(stream) => stream.stream.flush(), Stream::StandardOutput(stream) => stream.stream.flush(),
Stream::NamedHttpClient(_) | Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
Stream::HttpRead(_) |
Stream::StaticString(_) | Stream::StaticString(_) |
Stream::Readline(_) | Stream::Readline(_) |
Stream::InputFile(_) | Stream::InputFile(_) |
@@ -868,7 +912,8 @@ impl Stream {
Stream::StaticString(stream) => stream.past_end_of_stream, Stream::StaticString(stream) => stream.past_end_of_stream,
Stream::NamedTcp(stream) => stream.past_end_of_stream, Stream::NamedTcp(stream) => stream.past_end_of_stream,
Stream::NamedTls(stream) => stream.past_end_of_stream, Stream::NamedTls(stream) => stream.past_end_of_stream,
Stream::NamedHttpClient(stream) => stream.past_end_of_stream, Stream::HttpRead(stream) => stream.past_end_of_stream,
Stream::HttpWrite(stream) => stream.past_end_of_stream,
Stream::Null(_) => false, Stream::Null(_) => false,
Stream::Readline(stream) => stream.past_end_of_stream, Stream::Readline(stream) => stream.past_end_of_stream,
Stream::StandardOutput(stream) => stream.past_end_of_stream, Stream::StandardOutput(stream) => stream.past_end_of_stream,
@@ -890,7 +935,8 @@ impl Stream {
Stream::StaticString(stream) => stream.past_end_of_stream = value, Stream::StaticString(stream) => stream.past_end_of_stream = value,
Stream::NamedTcp(stream) => stream.past_end_of_stream = value, Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
Stream::NamedTls(stream) => stream.past_end_of_stream = value, Stream::NamedTls(stream) => stream.past_end_of_stream = value,
Stream::NamedHttpClient(stream) => stream.past_end_of_stream = value, Stream::HttpRead(stream) => stream.past_end_of_stream = value,
Stream::HttpWrite(stream) => stream.past_end_of_stream = value,
Stream::Null(_) => {} Stream::Null(_) => {}
Stream::Readline(stream) => stream.past_end_of_stream = value, Stream::Readline(stream) => stream.past_end_of_stream = value,
Stream::StandardOutput(stream) => stream.past_end_of_stream = value, Stream::StandardOutput(stream) => stream.past_end_of_stream = value,
@@ -956,11 +1002,11 @@ impl Stream {
Stream::Byte(_) Stream::Byte(_)
| Stream::Readline(_) | Stream::Readline(_)
| Stream::StaticString(_) | Stream::StaticString(_)
| Stream::NamedHttpClient(_) | Stream::HttpRead(_)
| Stream::InputFile(..) => atom!("read"), | Stream::InputFile(..) => atom!("read"),
Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"), Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
Stream::OutputFile(file) if file.is_append => atom!("append"), Stream::OutputFile(file) if file.is_append => atom!("append"),
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"), Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::HttpWrite(_) => atom!("write"),
Stream::Null(_) => atom!(""), Stream::Null(_) => atom!(""),
} }
} }
@@ -1020,8 +1066,8 @@ impl Stream {
http_stream: Box<dyn BufRead>, http_stream: Box<dyn BufRead>,
arena: &mut Arena, arena: &mut Arena,
) -> Self { ) -> Self {
Stream::NamedHttpClient(arena_alloc!( Stream::HttpRead(arena_alloc!(
StreamLayout::new(CharReader::new(NamedHttpClientStream { StreamLayout::new(CharReader::new(HttpReadStream {
url, url,
body_reader: http_stream body_reader: http_stream
})), })),
@@ -1029,6 +1075,19 @@ impl Stream {
)) ))
} }
#[inline]
pub(crate) fn from_http_sender(
body_writer: Sender,
arena: &mut Arena,
) -> Self {
Stream::HttpWrite(arena_alloc!(
StreamLayout::new(CharReader::new(HttpWriteStream {
body_writer
})),
arena
))
}
#[inline] #[inline]
pub(crate) fn from_file_as_output( pub(crate) fn from_file_as_output(
file_name: Atom, file_name: Atom,
@@ -1065,7 +1124,7 @@ impl Stream {
Stream::NamedTls(ref mut tls_stream) => { Stream::NamedTls(ref mut tls_stream) => {
tls_stream.inner_mut().tls_stream.shutdown() tls_stream.inner_mut().tls_stream.shutdown()
} }
Stream::NamedHttpClient(ref mut http_stream) => { Stream::HttpRead(ref mut http_stream) => {
unsafe { unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped); http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_reader as *mut _); std::ptr::drop_in_place(&mut http_stream.inner_mut().body_reader as *mut _);
@@ -1073,6 +1132,14 @@ impl Stream {
Ok(()) Ok(())
} }
Stream::HttpWrite(ref mut http_stream) => {
unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_writer as *mut _);
}
Ok(())
}
Stream::InputFile(mut file_stream) => { Stream::InputFile(mut file_stream) => {
// close the stream by dropping the inner File. // close the stream by dropping the inner File.
unsafe { unsafe {
@@ -1109,7 +1176,7 @@ impl Stream {
match self { match self {
Stream::NamedTcp(..) Stream::NamedTcp(..)
| Stream::NamedTls(..) | Stream::NamedTls(..)
| Stream::NamedHttpClient(..) | Stream::HttpRead(..)
| Stream::Byte(_) | Stream::Byte(_)
| Stream::Readline(_) | Stream::Readline(_)
| Stream::StaticString(_) | Stream::StaticString(_)
@@ -1124,7 +1191,8 @@ impl Stream {
Stream::StandardError(_) Stream::StandardError(_)
| Stream::StandardOutput(_) | Stream::StandardOutput(_)
| Stream::NamedTcp(..) | Stream::NamedTcp(..)
| Stream::NamedTls(..) | Stream::NamedTls(..)
| Stream::HttpWrite(..)
| Stream::Byte(_) | Stream::Byte(_)
| Stream::OutputFile(..) => true, | Stream::OutputFile(..) => true,
_ => false, _ => false,
@@ -1254,6 +1322,18 @@ impl MachineState {
None None
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
if name != atom!("[]") {
Some(name)
} else {
None
}
}
_ => { _ => {
None None
} }
@@ -1270,6 +1350,19 @@ impl MachineState {
_ => unreachable!(), _ => unreachable!(),
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
match name {
atom!("eof_code") => EOFAction::EOFCode,
atom!("error") => EOFAction::Error,
atom!("reset") => EOFAction::Reset,
_ => unreachable!(),
}
}
_ => { _ => {
unreachable!() unreachable!()
} }
@@ -1280,6 +1373,13 @@ impl MachineState {
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
name == atom!("true") name == atom!("true")
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => { _ => {
unreachable!() unreachable!()
} }
@@ -1294,6 +1394,17 @@ impl MachineState {
_ => unreachable!(), _ => unreachable!(),
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
match name {
atom!("text") => StreamType::Text,
atom!("binary") => StreamType::Binary,
_ => unreachable!(),
}
}
_ => { _ => {
unreachable!() unreachable!()
} }
@@ -1334,6 +1445,24 @@ impl MachineState {
} }
}; };
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
return match stream_aliases.get(&name) {
Some(stream) if !stream.is_null_stream() => Ok(*stream),
_ => {
let stub = functor_stub(caller, arity);
let addr = atom_as_cell!(name);
let existence_error = self.existence_error(ExistenceError::Stream(addr));
Err(self.error_form(existence_error, stub))
}
};
}
(HeapCellValueTag::Cons, ptr) => { (HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr, match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Stream, stream) => { (ArenaHeaderTag::Stream, stream) => {
@@ -1402,9 +1531,9 @@ impl MachineState {
arity: usize, arity: usize,
) -> MachineStub { ) -> MachineStub {
let stub = functor_stub(caller, arity); let stub = functor_stub(caller, arity);
let err = self.permission_error(perm, err_atom, stream_as_cell!(stream)); let err = self.permission_error(perm, err_atom, stream_as_cell!(stream));
return self.error_form(err, stub); self.error_form(err, stub)
} }
#[inline] #[inline]
@@ -1430,9 +1559,9 @@ impl MachineState {
stub_arity: usize, stub_arity: usize,
) -> MachineStub { ) -> MachineStub {
let stub = functor_stub(stub_name, stub_arity); let stub = functor_stub(stub_name, stub_arity);
let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit); let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit);
return self.error_form(err, stub); self.error_form(err, stub)
} }
pub(crate) fn occupied_alias_permission_error( pub(crate) fn occupied_alias_permission_error(
@@ -1442,24 +1571,22 @@ impl MachineState {
stub_arity: usize, stub_arity: usize,
) -> MachineStub { ) -> MachineStub {
let stub = functor_stub(stub_name, stub_arity); let stub = functor_stub(stub_name, stub_arity);
let alias_name = atom!("alias");
let err = self.permission_error( let err = self.permission_error(
Permission::Open, Permission::Open,
atom!("source_sink"), atom!("source_sink"),
functor!(alias_name, [atom(alias)]), functor!(atom!("alias"), [atom(alias)]),
); );
return self.error_form(err, stub); self.error_form(err, stub)
} }
pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub { pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
let stub = functor_stub(stub_name, stub_arity); let stub = functor_stub(stub_name, stub_arity);
let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]); let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub); let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
return self.error_form(err, stub); self.error_form(err, stub)
} }
pub(crate) fn check_stream_properties( pub(crate) fn check_stream_properties(

File diff suppressed because it is too large Load Diff

View File

@@ -119,3 +119,21 @@ impl TermStream for LiveTermStream {
&self.listing_src &self.listing_src
} }
} }
pub struct InlineTermStream {
}
impl TermStream for InlineTermStream {
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Err(CompilationError::from(ParserError::UnexpectedEOF))
}
fn eof(&mut self) -> Result<bool, CompilationError> {
Ok(true)
}
fn listing_src(&self) -> &ListingSource {
&ListingSource::User
}
}

View File

@@ -272,6 +272,26 @@ macro_rules! match_untyped_arena_ptr_pat_body {
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
($ptr:ident, HttpListener, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpListener>($ptr.payload_offset()) };
#[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, HttpResponse, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpResponse>($ptr.payload_offset()) };
#[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{
#[allow(unused_mut)]
let mut $ip = TypedArenaPtr::new(unsafe { std::mem::transmute::<_, *mut IndexPtr>($ptr.get_ptr()) });
#[allow(unused_braces)]
$code
}};
($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{ ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset()); let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
#[allow(unused_braces)] #[allow(unused_braces)]
@@ -285,13 +305,20 @@ macro_rules! match_untyped_arena_ptr_pat {
| ArenaHeaderTag::OutputFileStream | ArenaHeaderTag::OutputFileStream
| ArenaHeaderTag::NamedTcpStream | ArenaHeaderTag::NamedTcpStream
| ArenaHeaderTag::NamedTlsStream | ArenaHeaderTag::NamedTlsStream
| ArenaHeaderTag::NamedHttpClientStream | ArenaHeaderTag::HttpReadStream
| ArenaHeaderTag::HttpWriteStream
| ArenaHeaderTag::ReadlineStream | ArenaHeaderTag::ReadlineStream
| ArenaHeaderTag::StaticStringStream | ArenaHeaderTag::StaticStringStream
| ArenaHeaderTag::ByteStream | ArenaHeaderTag::ByteStream
| ArenaHeaderTag::StandardOutputStream | ArenaHeaderTag::StandardOutputStream
| ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::StandardErrorStream
}; };
(IndexPtr) => {
ArenaHeaderTag::IndexPtrUndefined |
ArenaHeaderTag::IndexPtrDynamicUndefined |
ArenaHeaderTag::IndexPtrDynamicIndex |
ArenaHeaderTag::IndexPtrIndex
};
($tag:ident) => { ($tag:ident) => {
ArenaHeaderTag::$tag ArenaHeaderTag::$tag
}; };

View File

@@ -1,5 +1,6 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::machine_indices::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::types::HeapCellValueTag; use crate::types::HeapCellValueTag;
@@ -530,6 +531,7 @@ impl Neg for Fixnum {
pub enum Literal { pub enum Literal {
Atom(Atom), Atom(Atom),
Char(char), Char(char),
CodeIndex(CodeIndex),
Fixnum(Fixnum), Fixnum(Fixnum),
Integer(TypedArenaPtr<Integer>), Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>), Rational(TypedArenaPtr<Rational>),
@@ -551,6 +553,7 @@ impl fmt::Display for Literal {
write!(f, "{}", atom.flat_index()) write!(f, "{}", atom.flat_index())
} }
Literal::Char(c) => write!(f, "'{}'", *c as u32), Literal::Char(c) => write!(f, "'{}'", *c as u32),
Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
Literal::Fixnum(n) => write!(f, "{}", n.get_num()), Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
Literal::Integer(ref n) => write!(f, "{}", n), Literal::Integer(ref n) => write!(f, "{}", n),
Literal::Rational(ref n) => write!(f, "{}", n), Literal::Rational(ref n) => write!(f, "{}", n),

View File

@@ -1,5 +1,6 @@
use lexical::parse_lossy; use lexical::parse_lossy;
use crate::arena::ArenaAllocated;
use crate::atom_table::*; use crate::atom_table::*;
pub use crate::machine::machine_state::*; pub use crate::machine::machine_state::*;
use crate::parser::ast::*; use crate::parser::ast::*;

View File

@@ -336,7 +336,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.push_stub_addr(); self.push_stub_addr();
self.push_stub_addr(); self.push_stub_addr();
} }
&TermRef::Clause(Level::Root, _, ref ct, subterms) => { &TermRef::Clause(Level::Root, _, name, subterms) => {
if subterms.len() > MAX_ARITY { if subterms.len() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity); return Err(CompilationError::ExceededMaxArity);
} }
@@ -348,7 +348,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
}); });
self.queue.push_back((subterms.len(), h + 2)); self.queue.push_back((subterms.len(), h + 2));
let named = atom_as_cell!(ct.name(), subterms.len()); let named = atom_as_cell!(name, subterms.len());
self.heap.push(named); self.heap.push(named);
@@ -358,9 +358,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
continue; continue;
} }
&TermRef::Clause(_, _, ref ct, subterms) => { &TermRef::Clause(_, _, name, subterms) => {
self.queue.push_back((subterms.len(), h + 1)); self.queue.push_back((subterms.len(), h + 1));
let named = atom_as_cell!(ct.name(), subterms.len()); let named = atom_as_cell!(name, subterms.len());
self.heap.push(named); self.heap.push(named);
@@ -390,6 +390,12 @@ impl<'a, 'b> TermWriter<'a, 'b> {
put_complete_string(self.heap, src.as_str(), self.atom_tbl); put_complete_string(self.heap, src.as_str(), self.atom_tbl);
} }
&TermRef::PartialString(lvl, _, ref src, _) => { &TermRef::PartialString(lvl, _, ref src, _) => {
if let Level::Root = lvl {
// Var tags can't refer directly to partial strings,
// so a PStrLoc cell must be pushed.
self.heap.push(pstr_loc_as_cell!(heap_loc + 1));
}
allocate_pstr(self.heap, src.as_str(), self.atom_tbl); allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
let h = self.heap.len(); let h = self.heap.len();

View File

@@ -172,7 +172,7 @@ instruction_match(Term, VarList) :-
; Term = end_of_file -> ; Term = end_of_file ->
halt halt
; ;
submit_query_and_print_results(Term, VarList) submit_query_and_print_results(Term, VarList)
). ).
@@ -180,7 +180,7 @@ submit_query_and_print_results_(Term, VarList) :-
'$get_b_value'(B), '$get_b_value'(B),
bb_put('$report_all', false), bb_put('$report_all', false),
bb_put('$report_n_more', 0), bb_put('$report_n_more', 0),
'$call'(Term), call(user:Term),
write_eqs_and_read_input(B, VarList), write_eqs_and_read_input(B, VarList),
!. !.
submit_query_and_print_results_(_, _) :- submit_query_and_print_results_(_, _) :-
@@ -192,12 +192,12 @@ submit_query_and_print_results_(_, _) :-
nl. nl.
submit_query_and_print_results(Term0, VarList) :- submit_query_and_print_results(Term, VarList) :-
( functor(Term0, call, _) -> % ( functor(Term0, call, _) ->
Term = Term0 % prevent pre-mature expansion of incomplete goal % Term = Term0 % prevent pre-mature expansion of incomplete goal
% in the first argument, which is done by call/N % % in the first argument, which is done by call/N
; expand_goal(Term0, user, Term) % ; expand_goal(Term0, user, Term)
), % ),
bb_put('$answer_count', 0), bb_put('$answer_count', 0),
submit_query_and_print_results_(Term, VarList). submit_query_and_print_results_(Term, VarList).
@@ -301,6 +301,7 @@ write_eqs_and_read_input(B, VarList) :-
append(Equations, AttrGoals, Goals), append(Equations, AttrGoals, Goals),
% one layer of depth added for (=/2) functor % one layer of depth added for (=/2) functor
maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars), maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
% maplist(term_variables_under_max_depth(22), Equations, EquationVars),
append([AttrGoalVars | EquationVars], Vars1), append([AttrGoalVars | EquationVars], Vars1),
term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order. term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated), charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),

View File

@@ -301,7 +301,7 @@ impl fmt::Debug for HeapCellValue {
} }
} }
impl<T> From<TypedArenaPtr<T>> for HeapCellValue { impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue {
#[inline] #[inline]
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue { fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
HeapCellValue::from(arena_ptr.header_ptr() as u64) HeapCellValue::from(arena_ptr.header_ptr() as u64)
@@ -441,20 +441,22 @@ impl HeapCellValue {
} }
#[inline] #[inline]
pub fn is_compound(self) -> bool { pub fn is_compound(self, heap: &[HeapCellValue]) -> bool {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Str HeapCellValueTag::Str => {
| HeapCellValueTag::Lis cell_as_atom_cell!(heap[self.get_value()]).get_arity() > 0
| HeapCellValueTag::CStr }
| HeapCellValueTag::PStr HeapCellValueTag::Lis |
| HeapCellValueTag::PStrLoc HeapCellValueTag::CStr |
| HeapCellValueTag::PStrOffset => { HeapCellValueTag::PStr |
HeapCellValueTag::PStrLoc |
HeapCellValueTag::PStrOffset => {
true true
} }
HeapCellValueTag::Atom => { HeapCellValueTag::Atom => {
cell_as_atom_cell!(self).get_arity() > 0 cell_as_atom_cell!(self).get_arity() > 0
} }
_ => { false } _ => { false }
} }
} }
@@ -582,7 +584,7 @@ impl HeapCellValue {
} }
} }
pub fn order_category(self) -> Option<TermOrderCategory> { pub fn order_category(self, heap: &[HeapCellValue]) -> Option<TermOrderCategory> {
match Number::try_from(self).ok() { match Number::try_from(self).ok() {
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
Some(TermOrderCategory::Integer) Some(TermOrderCategory::Integer)
@@ -601,9 +603,19 @@ impl HeapCellValue {
}) })
} }
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr | HeapCellValueTag::Str => { HeapCellValueTag::CStr => {
Some(TermOrderCategory::Compound) Some(TermOrderCategory::Compound)
} }
HeapCellValueTag::Str => {
let value = heap[self.get_value()];
let arity = cell_as_atom_cell!(value).get_arity();
if arity == 0 {
Some(TermOrderCategory::Atom)
} else {
Some(TermOrderCategory::Compound)
}
}
_ => { _ => {
None None
} }
@@ -628,7 +640,7 @@ const_assert!(mem::size_of::<HeapCellValue>() == 8);
#[bitfield] #[bitfield]
#[repr(u64)] #[repr(u64)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct UntypedArenaPtr { pub struct UntypedArenaPtr {
ptr: B61, ptr: B61,
m: bool, m: bool,
@@ -644,6 +656,13 @@ impl From<*const ArenaHeader> for UntypedArenaPtr {
} }
} }
impl From<*const IndexPtr> for UntypedArenaPtr {
#[inline]
fn from(ptr: *const IndexPtr) -> UntypedArenaPtr {
unsafe { mem::transmute(ptr) }
}
}
impl From<UntypedArenaPtr> for *const ArenaHeader { impl From<UntypedArenaPtr> for *const ArenaHeader {
#[inline] #[inline]
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader { fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {